Exemple #1
0
 def _createmap(self, obj):
     """
     Create all markers for each people's event in the database which has
     a lat/lon.
     """
     if self.osm is None:
         return
     dbstate = self.dbstate
     self.place_list = []
     self.places_found = []
     self.place_without_coordinates = []
     self.minlat = self.maxlat = self.minlon = self.maxlon = 0.0
     self.minyear = 9999
     self.maxyear = 0
     self.nbmarkers = 0
     self.nbplaces = 0
     self.without = 0
     self.cal = config.get('preferences.calendar-format-report')
     self.message_layer.clear_messages()
     self.message_layer.clear_font_attributes()
     self.no_show_places_in_status_bar = False
     if self.show_all:
         self.show_all = False
         events_handle = dbstate.db.get_event_handles()
         progress = ProgressMeter(self.window_name,
                                  can_cancel=False,
                                  parent=self.uistate.window)
         length = len(events_handle)
         progress.set_pass(_('Selecting all events'), length)
         for event_hdl in events_handle:
             event = dbstate.db.get_event_from_handle(event_hdl)
             self._createmap_for_one_event(event)
             progress.step()
         progress.close()
     elif self.generic_filter:
         user = self.uistate.viewmanager.user
         events_list = self.generic_filter.apply(dbstate.db, user=user)
         progress = ProgressMeter(self.window_name,
                                  can_cancel=False,
                                  parent=self.uistate.window)
         length = len(events_list)
         progress.set_pass(_('Selecting all events'), length)
         for event_handle in events_list:
             event = dbstate.db.get_event_from_handle(event_handle)
             self._createmap_for_one_event(event)
             progress.step()
         progress.close()
     else:
         if obj:
             event = dbstate.db.get_event_from_handle(obj)
             self._createmap_for_one_event(event)
         self.message_layer.add_message(
             _("Right click on the map and select 'show all events'"
               " to show all known events with coordinates. "
               "You can use the history to navigate on the map. "
               "You can use filtering."))
     self.sort = sorted(self.place_list, key=operator.itemgetter(3, 4, 6))
     if self.nbmarkers > 500:  # performance issue. Is it the good value ?
         self.no_show_places_in_status_bar = True
     self._create_markers()
Exemple #2
0
    def generate_md5(self, button):
        """
        Generate md5 hashes for media files.
        """
        self.clear_models()

        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_media()
        progress.set_pass(_('Generating media hashes'), length)

        with DbTxn(_("Set media hashes"), self.db, batch=True) as trans:

            for handle in self.db.get_media_handles():
                media = self.db.get_media_from_handle(handle)

                full_path = media_path_full(self.db, media.get_path())
                md5sum = create_checksum(full_path)
                if not md5sum:
                    error_msg = 'IOError: %s' % full_path
                    self.models[5].append((error_msg, None))
                    progress.step()
                    continue

                media.set_checksum(md5sum)
                self.db.commit_media(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.show_tabs()
        progress.close()
Exemple #3
0
 class User2:
     """
     Helper class to provide "can_cancel" functionality to
     the progress indicator used by gramps.gen.filters._genericfilter.GenericFilter.apply().
     Replaces the gramps.gui.user.User class for this case.
     Code copied from gramps/gui/user.py.
     """
     def __init__(self, user):
         self.parent = user.parent
         self.uistate = user.uistate
         self.parent = user.parent
     def begin_progress(self, title, message, steps):
         # Parameter "can_cancel" added to ProgressMeter creation.
         from gramps.gui.utils import ProgressMeter
         self._progress = ProgressMeter(title, parent=self.parent, can_cancel=True)
         if steps > 0:
             self._progress.set_pass(message, steps, ProgressMeter.MODE_FRACTION)
         else:
             self._progress.set_pass(message, mode=ProgressMeter.MODE_ACTIVITY)
     def step_progress(self):
         res = self._progress.step()
         if res:
             self.end_progress()
             raise StopIteration
     def end_progress(self):
         self._progress.close()
         self._progress = None
    def generate_md5(self, button):
        """
        Generate md5 hashes for media files.
        """
        self.clear_models()

        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_media()
        progress.set_pass(_('Generating media hashes'), length)

        with DbTxn(_("Set media hashes"), self.db, batch=True) as trans:

            for handle in self.db.get_media_handles():
                media = self.db.get_media_from_handle(handle)

                full_path = media_path_full(self.db, media.get_path())
                md5sum = create_checksum(full_path)
                if not md5sum:
                    error_msg = 'IOError: %s' % full_path
                    self.models[5].append((error_msg, None))
                    progress.step()
                    continue

                media.set_checksum(md5sum)
                self.db.commit_media(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.show_tabs()
        progress.close()
Exemple #5
0
    def model_load(self):
        """ populate the tree with types """
        r_indx = 0
        self.model.clear()
        for (attr, name, _obj, _srcobj) in self.t_table:
            # 99 is indicator that row is a title row
            row = (name, 0, 99)
            iter_ = self.model.append(None, row)
            # get custom types from db
            types = getattr(self.db, attr, None)
            if types is None:
                continue
            for indx, cust_type in enumerate(types):
                # update right model
                row = (cust_type, indx, r_indx)
                self.model.append(iter_, row)
                # create refs list for the custom type
                self.types_dict[_obj][cust_type] = []
            r_indx += 1
        progress = ProgressMeter(self.window_name,
                                 can_cancel=False,
                                 parent=self.window)
        # find total of db objects
        total = 0
        for obj_type in self.primary_objects_pl:
            total += self.db.method('get_number_of_%s', obj_type)()

        # scan db objects and record all custom GrampsTypes found as references
        progress.set_pass(_("Reading database..."), total)
        for obj_type in self.primary_objects:
            for hndl in self.db.method('get_%s_handles', obj_type)():
                obj = self.db.method('get_%s_from_handle', obj_type)(hndl)
                self.do_recurse(obj, obj_type, hndl)
                progress.step()
        progress.close()
Exemple #6
0
    def saveit(self, button):
        """
        Commit the changes to the database
        """
        self.update_changelist()
        progress = ProgressMeter(self.window_name,
                                 can_cancel=True,
                                 parent=self.window)

        length = len(self.changelist)
        progress.set_pass(_('Saving Notes'), length)

        with DbTxn(_("Saving Cleaned Notes"), self.db, batch=False) as trans:
            for changed in self.changelist:
                note = self.db.get_note_from_handle(changed[0])
                note.set_styledtext(changed[2])
                self.db.commit_note(note, trans)
                msg = _("Note Cleanup")
                trans.set_description(msg)
                progress.step()
                if progress.get_cancelled():
                    break
        self.clear_models()
        self.show_tabs()
        progress.close()
Exemple #7
0
 def display(self):
     try:
         from bsddb3.db import DBError
     except:
         class DBError(Exception):
             """
             Dummy.
             """
     self.parent = self.top.get_toplevel()
     progress = ProgressMeter(
         _('Updating display...'), '', parent=self.parent, can_cancel=True)
     self.model.clear()
     self.junk = []
     gc.collect(2)
     self.junk = gc.garbage
     self.label.set_text(_('Uncollected Objects: %s') %
                         str(len(self.junk)))
     progress.set_pass(_('Updating display...'), len(self.junk))
     for count in range(0, len(self.junk)):
         if progress.step():
             break
         try:
             refs = []
             referrers = gc.get_referrers(self.junk[count])
             for referrer in referrers:
                 try:
                     if referrer is not self.junk:
                         for indx in range(0, len(self.junk)):
                             if referrer is self.junk[indx]:
                                 refs.append(str(indx) + ' ')
                                 break
                 except:
                     print(sys.exc_info())
             if len(refs) > 3:
                 ref = ' '.join(refs[0:2]) + "..."
             else:
                 ref = ' '.join(refs)
             try:
                 self.model.append((count, ref, str(self.junk[count])))
             except DBError:
                 self.model.append((count, ref,
                                   'db.DB instance at %s' %
                                    id(self.junk[count])))
             except ReferenceError:
                 self.model.append((
                     count, ref,
                     'weakly-referenced object no longer exists %s'
                     % type(self.junk[count])))
             except TypeError:
                 self.model.append((
                     count, ref,
                     'Object cannot be displayed %s'
                     % type(self.junk[count])))
             except:
                 print(sys.exc_info())
         except ReferenceError:
             InfoDialog(_('Reference Error'), "Refresh to correct",
                        parent=self.parent)
     progress.close()
Exemple #8
0
 def display(self):
     try:
         from bsddb3.db import DBError
     except:
         class DBError(Exception):
             """
             Dummy.
             """
     self.parent = self.top.get_toplevel()
     progress = ProgressMeter(
         _('Updating display...'), '', parent=self.parent, can_cancel=True)
     self.model.clear()
     self.junk = []
     gc.collect(2)
     self.junk = gc.garbage
     self.label.set_text(_('Uncollected Objects: %s') %
                         str(len(self.junk)))
     progress.set_pass(_('Updating display...'), len(self.junk))
     for count in range(0, len(self.junk)):
         if progress.step():
             break
         try:
             refs = []
             referrers = gc.get_referrers(self.junk[count])
             for referrer in referrers:
                 try:
                     if referrer is not self.junk:
                         for indx in range(0, len(self.junk)):
                             if referrer is self.junk[indx]:
                                 refs.append(str(indx) + ' ')
                                 break
                 except:
                     print(sys.exc_info())
             if len(refs) > 3:
                 ref = ' '.join(refs[0:2]) + "..."
             else:
                 ref = ' '.join(refs)
             try:
                 self.model.append((count, ref, str(self.junk[count])))
             except DBError:
                 self.model.append((count, ref,
                                   'db.DB instance at %s' %
                                    id(self.junk[count])))
             except ReferenceError:
                 self.model.append((
                     count, ref,
                     'weakly-referenced object no longer exists %s'
                     % type(self.junk[count])))
             except TypeError:
                 self.model.append((
                     count, ref,
                     'Object cannot be displayed %s'
                     % type(self.junk[count])))
             except:
                 print(sys.exc_info())
         except ReferenceError:
             InfoDialog(_('Reference Error'), "Refresh to correct",
                        parent=self.parent)
     progress.close()
Exemple #9
0
    def applyTagClicked(self, button):
        progress = None
        rows = self.treeSelection.count_selected_rows()
        tag_name = str(self.tagcombo.get_active_text())

        # start the db transaction
        with DbTxn("Tag not related", self.db) as transaction:

            tag = self.db.get_tag_from_name(tag_name)
            if not tag:
                # create the tag if it doesn't already exist
                tag = Tag()
                tag.set_name(tag_name)
                tag.set_priority(self.db.get_number_of_tags())
                tag_handle = self.db.add_tag(tag, transaction)
            else:
                tag_handle = tag.get_handle()

            # if more than 1 person is selected, use a progress indicator
            if rows > 1:
                progress = ProgressMeter(self.title, _('Starting'))
                progress.set_pass(
                    # translators: leave all/any {...} untranslated
                    #TRANS: no singular form needed, as rows is always > 1
                    ngettext("Setting tag for {number_of} person",
                             "Setting tag for {number_of} people",
                             rows).format(number_of=rows),
                    rows)

            # iterate through all of the selected rows
            (model, paths) = self.treeSelection.get_selected_rows()

            for path in paths:
                if progress:
                    progress.step()

                # for the current row, get the GID and the person from the database
                iter = self.model.get_iter(path)
                personGid = self.model.get_value(iter, 1)
                person = self.db.get_person_from_gramps_id(personGid)

                # add the tag to the person
                person.add_tag(tag_handle)

                # save this change
                self.db.commit_person(person, transaction)

        # refresh the tags column
        self.treeView.set_model(None)
        for path in paths:
            iter = self.model.get_iter(path)
            personGid = self.model.get_value(iter, 1)
            person = self.db.get_person_from_gramps_id(personGid)
            self.model.set_value(iter, 3, self.get_tag_list(person))
        self.treeView.set_model(self.model)
        self.treeView.expand_all()

        if progress:
            progress.close()
    def cleanup(self, _button):
        """
        Cleanup Notes.
        """
        self.clear_models()

        StyledText.__getitem__ = MyStyled.__getitem__  # patch in slice func

        progress = ProgressMeter(self.window_name,
                                 can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_notes()
        progress.set_pass(_('Scanning Notes'), length)

        for handle in self.db.get_note_handles():
            note = self.db.get_note_from_handle(handle)
            g_id = note.gramps_id
            stext = note.get_styledtext()
            optype = -1
            # find the notes and do cleanup
            #if not stext.tags:
            text = StyledText(stext._string, stext._tags)  # make a copy
            result = self.convert_to_styled(text)
            indx = len(self.changelist)
            for styledtext_tag in result.tags:
                if (int(styledtext_tag.name) == StyledTextTagType.HIGHLIGHT
                        and '#FFFF00' == styledtext_tag.value):
                    optype = ISSUE
                    break
                elif int(styledtext_tag.name) == StyledTextTagType.LINK:
                    optype = LINK
            while True:
                if optype == ISSUE:
                    # make list of notes with errors
                    self.models[ISSUE].append((self.preview(stext,
                                                            g_id), indx))
                elif stext._string != result._string:
                    # Make list of edited notes
                    self.models[CLEANED].append((self.preview(stext,
                                                              g_id), indx))
                elif optype == LINK:
                    # make list of notes with only links
                    self.models[LINK].append((self.preview(stext, g_id), indx))
                else:
                    break
                self.changelist.append((handle, stext, result))
                break

            progress.step()
            if progress.get_cancelled():
                break

        self.show_tabs()
        progress.close()
Exemple #11
0
 def _createmap(self, obj):
     """
     Create all markers for each people's event in the database which has
     a lat/lon.
     """
     dbstate = self.dbstate
     self.place_list = []
     self.places_found = []
     self.place_without_coordinates = []
     self.minlat = self.maxlat = self.minlon = self.maxlon = 0.0
     self.minyear = 9999
     self.maxyear = 0
     self.nbmarkers = 0
     self.nbplaces = 0
     self.without = 0
     self.cal = config.get('preferences.calendar-format-report')
     self.no_show_places_in_status_bar = False
     if self.show_all:
         self.show_all = False
         events_handle = dbstate.db.get_event_handles()
         progress = ProgressMeter(self.window_name,
                                  can_cancel=False,
                                  parent=self.uistate.window)
         length = len(events_handle)
         progress.set_pass(_('Selecting all events'), length)
         for event_hdl in events_handle:
             event = dbstate.db.get_event_from_handle(event_hdl)
             self._createmap_for_one_event(event)
             progress.step()
         progress.close()
     elif self.generic_filter:
         user=self.uistate.viewmanager.user
         events_list = self.generic_filter.apply(dbstate.db, user=user)
         progress = ProgressMeter(self.window_name,
                                  can_cancel=False,
                                  parent=self.uistate.window)
         length = len(events_list)
         progress.set_pass(_('Selecting all events'), length)
         for event_handle in events_list:
             event = dbstate.db.get_event_from_handle(event_handle)
             self._createmap_for_one_event(event)
             progress.step()
         progress.close()
     elif obj:
         event = dbstate.db.get_event_from_handle(obj)
         self._createmap_for_one_event(event)
     self.sort = sorted(self.place_list,
                        key=operator.itemgetter(3, 4, 6)
                       )
     if self.nbmarkers > 500: # performance issue. Is it the good value ?
         self.no_show_places_in_status_bar = True
     self._create_markers()
Exemple #12
0
 def _createmap(self, obj):
     """
     Create all markers for each people's event in the database which has
     a lat/lon.
     """
     dbstate = self.dbstate
     self.place_list = []
     self.places_found = []
     self.place_without_coordinates = []
     self.minlat = self.maxlat = self.minlon = self.maxlon = 0.0
     self.minyear = 9999
     self.maxyear = 0
     self.nbmarkers = 0
     self.nbplaces = 0
     latitude = ""
     longitude = ""
     self.without = 0
     self.cal = config.get('preferences.calendar-format-report')
     self.no_show_places_in_status_bar = False
     if self.show_all:
         self.show_all = False
         events_handle = dbstate.db.get_event_handles()
         progress = ProgressMeter(self.window_name,
                                  can_cancel=False,
                                  parent=self.uistate.window)
         length = len(events_handle)
         progress.set_pass(_('Selecting all events'), length)
         for event_hdl in events_handle:
             event = dbstate.db.get_event_from_handle(event_hdl)
             self._createmap_for_one_event(event)
             progress.step()
         progress.close()
     elif self.generic_filter:
         events_list = self.generic_filter.apply(dbstate.db)
         progress = ProgressMeter(self.window_name,
                                  can_cancel=False,
                                  parent=self.uistate.window)
         length = len(events_list)
         progress.set_pass(_('Selecting all events'), length)
         for event_handle in events_list:
             event = dbstate.db.get_event_from_handle(event_handle)
             self._createmap_for_one_event(event)
             progress.step()
         progress.close()
     elif obj:
         event = dbstate.db.get_event_from_handle(obj)
         self._createmap_for_one_event(event)
     self.sort = sorted(self.place_list, key=operator.itemgetter(3, 4, 6))
     if self.nbmarkers > 500:  # performance issue. Is it the good value ?
         self.no_show_places_in_status_bar = True
     self._create_markers()
Exemple #13
0
    def cleanup(self, button):
        """
        Cleanup Notes.
        """
        self.clear_models()

        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_notes()
        progress.set_pass(_('Scanning Notes'), length)

        for handle in self.db.get_note_handles():
            note = self.db.get_note_from_handle(handle)
            g_id = note.gramps_id
            stext = note.get_styledtext()
            handle = handle.decode('utf-8')
            optype = -1
            ## find the notes and do cleanup
            if not stext.tags:
                result = self.convert_to_styled(stext.string)
                indx = len(self.changelist)
                for styledtext_tag in result.tags:
                    if int(styledtext_tag.name) == StyledTextTagType.HIGHLIGHT:
                        optype = ISSUE
                        break
                    elif int(styledtext_tag.name) == StyledTextTagType.LINK:
                        optype = LINK
                while True:
                    if optype == ISSUE:
                        # make list of notes with errors
                        self.models[ISSUE].append((self.preview(stext, g_id), indx))
                    elif stext.string != result.string:
                        # Make list of edited notes
                        self.models[CLEANED].append((self.preview(stext, g_id), indx))
                    elif optype == LINK:
                        # make list of notes with only links
                        self.models[LINK].append((self.preview(stext, g_id), indx))
                    else:
                        break
                    self.changelist.append((handle, stext, result))
                    break

            progress.step()
            if progress.get_cancelled():
                break

        self.show_tabs()
        progress.close()
Exemple #14
0
    def generate_md5(self, button):
        """
        Generate md5 hashes for media files and attach them as attributes to
        media objects.
        """
        self.clear_models()

        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_media_objects()
        progress.set_pass(_('Generating media hashes'), length)

        with DbTxn(_("Set media hashes"), self.db, batch=True) as trans:

            for handle in self.db.get_media_object_handles():
                media = self.db.get_object_from_handle(handle)

                full_path = media_path_full(self.db, media.get_path())
                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

                for attr in media.get_attribute_list():
                    if str(attr.get_type()) == 'md5':
                        media.remove_attribute(attr)
                        break

                attr = Attribute()
                attr.set_type(AttributeType('md5'))
                attr.set_value(md5sum)

                media.add_attribute(attr)
                
                self.db.commit_media_object(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.show_tabs()
        progress.close()
Exemple #15
0
class FixCoords(tool.BatchTool):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        if dbstate.db.readonly:
            return

        self.progress = ProgressMeter(_("Fix Coordinates"),
                                      _('Starting'),
                                      parent=uistate.window)
        uistate.set_busy_cursor(True)
        dbstate.db.disable_signals()
        steps = dbstate.db.get_number_of_places()
        self.progress.set_pass(
            _('Looking for possible coords with ","'
              ' characters'), steps)
        with DbTxn(_("Fix coords"), dbstate.db, batch=False) as trans:
            for place_handle in dbstate.db.get_place_handles():
                self.progress.step()
                place = dbstate.db.get_place_from_handle(place_handle)
                place_name = place.get_name()
                pname = place_name.get_value()
                found = False
                if pname != pname.strip():
                    found = True
                    place_name.set_value(pname.strip())
                plat = place.get_latitude()
                if plat != plat.strip().replace(',', '.'):
                    found = True
                    place.set_latitude(plat.strip().replace(',', '.'))
                plon = place.get_longitude()
                if plon != plon.strip().replace(',', '.'):
                    found = True
                    place.set_longitude(plon.strip().replace(',', '.'))
                if found:
                    dbstate.db.commit_place(place, trans)

        uistate.set_busy_cursor(False)
        # close the progress bar
        self.progress.close()
        dbstate.db.enable_signals()
        dbstate.db.request_rebuild()
Exemple #16
0
    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)
Exemple #17
0
    def on_apply_clicked(self, obj):
        cfilter = self.filter_model[self.filters.get_active()][1]

        progress_bar = ProgressMeter(_("Comparing events"), "", parent=self.window)
        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"), parent=self.window)
        else:
            DisplayChart(self.dbstate, self.uistate, plist, self.track)
    def prepare(self, db):
        # FIXME: this should user the User class
        from gramps.gui.utils import ProgressMeter
        root_person_id = self.list[0]
        root_person = db.get_person_from_gramps_id(root_person_id)

        progress = ProgressMeter(_('Finding relationship paths'))
        progress.set_pass(header=_('Evaluating people'), mode=ProgressMeter.MODE_ACTIVITY)

        filter_name = self.list[1]
        target_people = filter_database(db, progress, filter_name)

        paths = find_deep_relations(db, progress, root_person, [], [], target_people)

        progress.close()
        progress = None

        self.__matches = set()
        list(map(self.__matches.update, paths))
    def prepare(self, db):
        # FIXME: this should user the User class
        from gramps.gui.utils import ProgressMeter
        root_person_id = self.list[0]
        root_person = db.get_person_from_gramps_id(root_person_id)

        progress = ProgressMeter(_('Finding relationship paths'))
        progress.set_pass(header=_('Evaluating people'), mode=ProgressMeter.MODE_ACTIVITY)

        filter_name = self.list[1]
        target_people = filter_database(db, progress, filter_name)

        paths = find_deep_relations(db, progress, root_person, [], [], target_people)

        progress.close()
        progress = None

        self.__matches = set()
        list(map(self.__matches.update, paths))
Exemple #20
0
    def fix_media(self, button):
        """
        Fix paths to moved media files.
        """
        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)
        progress.set_pass(_('Fixing file paths'), len(self.moved_files))

        with DbTxn(_("Fix media paths"), self.db, batch=True) as trans:

            for handle, new_path in self.moved_files:
                media = self.db.get_object_from_handle(handle)
                media.set_path(new_path)
                self.db.commit_media_object(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.models[0].clear()
        self.show_tabs()
        progress.close()
Exemple #21
0
    def fix_media(self, button):
        """
        Fix paths to moved media files.
        """
        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)
        progress.set_pass(_('Fixing file paths'), len(self.moved_files))

        with DbTxn(_("Fix media paths"), self.db, batch=True) as trans:

            for handle, new_path in self.moved_files:
                media = self.db.get_media_from_handle(handle)
                media.set_path(new_path)
                self.db.commit_media(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.models[0].clear()
        self.show_tabs()
        progress.close()
Exemple #22
0
    def generate_md5(self, button):
        """
        Generate md5 hashes for media files.
        """
        self.clear_models()

        progress = ProgressMeter(self.window_name,
                                 can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_media()
        progress.set_pass(_('Generating media hashes'), length)

        with DbTxn(_("Set media hashes"), self.db, batch=True) as trans:

            for handle in self.db.get_media_handles():
                media = self.db.get_media_from_handle(handle)

                full_path = media_path_full(self.db, media.get_path())
                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

                media.set_checksum(md5sum)
                self.db.commit_media(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.show_tabs()
        progress.close()
    def saveit(self, button):
        """
        Commit the changes to the database
        """
        self.update_changelist()
        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)

        length = len(self.changelist)
        progress.set_pass(_('Saving Notes'), length)

        with DbTxn(_("Saving Cleaned Notes"), self.db, batch=False) as trans:
            for changed in self.changelist:
                note = self.db.get_note_from_handle(changed[0])
                note.set_styledtext(changed[2])
                self.db.commit_note(note, trans)
                msg = _("Note Cleanup")
                trans.set_description(msg)
                progress.step()
                if progress.get_cancelled():
                    break
        self.clear_models()
        self.show_tabs()
        progress.close()
    def generate_md5(self, button):
        """
        Generate md5 hashes for media files.
        """
        self.clear_models()

        progress = ProgressMeter(self.window_name, can_cancel=True,
                                 parent=self.window)

        length = self.db.get_number_of_media()
        progress.set_pass(_('Generating media hashes'), length)

        with DbTxn(_("Set media hashes"), self.db, batch=True) as trans:

            for handle in self.db.get_media_handles():
                media = self.db.get_media_from_handle(handle)

                full_path = media_path_full(self.db, media.get_path())
                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

                media.set_checksum(md5sum)
                self.db.commit_media(media, trans)

                progress.step()
                if progress.get_cancelled():
                    break

        self.show_tabs()
        progress.close()
Exemple #25
0
class Merge(tool.Tool,ManagedWindow):

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        tool.Tool.__init__(self, dbstate, options_class, name)
        ManagedWindow.__init__(self, uistate, [],
                                             self.__class__)
        self.dbstate = dbstate
        self.uistate = uistate
        self.map = {}
        self.list = []
        self.index = 0
        self.merger = None
        self.mergee = None
        self.removed = {}
        self.update = callback
        self.use_soundex = 1

        top = Glade()

        # retrieve options
        threshold = self.options.handler.options_dict['threshold']
        use_soundex = self.options.handler.options_dict['soundex']

        my_menu = Gtk.ListStore(str, object)
        for val in sorted(_val2label):
            my_menu.append([_val2label[val], val])

        self.soundex_obj = top.get_object("soundex")
        self.soundex_obj.set_active(use_soundex)
        self.soundex_obj.show()

        self.menu = top.get_object("menu")
        self.menu.set_model(my_menu)
        self.menu.set_active(0)

        window = top.toplevel
        self.set_window(window, top.get_object('title'),
                        _('Find Possible Duplicate People'))

        top.connect_signals({
            "on_do_merge_clicked"   : self.__dummy,
            "on_help_show_clicked"  : self.__dummy,
            "on_delete_show_event"  : self.__dummy,
            "on_merge_ok_clicked"   : self.on_merge_ok_clicked,
            "destroy_passed_object" : self.close,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_merge_event" : self.close,
            "on_delete_event"       : self.close,
            })

        self.show()

    def build_menu_names(self, obj):
        return (_("Tool settings"),_("Find Duplicates tool"))

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""

        display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC)

    def ancestors_of(self, p1_id, id_list):
        if (not p1_id) or (p1_id in id_list):
            return
        id_list.append(p1_id)
        p1 = self.db.get_person_from_handle(p1_id)
        f1_id = p1.get_main_parents_family_handle()
        if f1_id:
            f1 = self.db.get_family_from_handle(f1_id)
            self.ancestors_of(f1.get_father_handle(),id_list)
            self.ancestors_of(f1.get_mother_handle(),id_list)

    def on_merge_ok_clicked(self, obj):
        threshold = self.menu.get_model()[self.menu.get_active()][1]
        self.use_soundex = int(self.soundex_obj.get_active())
        try:
            self.find_potentials(threshold)
        except AttributeError as msg:
            RunDatabaseRepair(str(msg), parent=self.window)
            return

        self.options.handler.options_dict['threshold'] = threshold
        self.options.handler.options_dict['soundex'] = self.use_soundex
        # Save options
        self.options.handler.save_options()

        if len(self.map) == 0:
            OkDialog(
                _("No matches found"),
                _("No potential duplicate people were found"),
                parent=self.window)
        else:
            try:
                ShowMatches(self.dbstate,self.uistate,self.track,
                            self.list,self.map,self.update)
            except WindowActiveError:
                pass

    def find_potentials(self, thresh):
        self.progress = ProgressMeter(_('Find Duplicates'),
                                      _('Looking for duplicate people'),
                                      parent=self.window)

        index = 0
        males = {}
        females = {}

        length = self.db.get_number_of_people()

        self.progress.set_pass(_('Pass 1: Building preliminary lists'),
                               length)

        for p1_id in self.db.iter_person_handles():
            self.progress.step()
            p1 = self.db.get_person_from_handle(p1_id)
            key = self.gen_key(get_surnames(p1.get_primary_name()))
            if p1.get_gender() == Person.MALE:
                if key in males:
                    males[key].append(p1_id)
                else:
                    males[key] = [p1_id]
            else:
                if key in females:
                    females[key].append(p1_id)
                else:
                    females[key] = [p1_id]

        self.progress.set_pass(_('Pass 2: Calculating potential matches'),
                               length)

        for p1key in self.db.iter_person_handles():
            self.progress.step()
            p1 = self.db.get_person_from_handle(p1key)

            key = self.gen_key(get_surnames(p1.get_primary_name()))
            if p1.get_gender() == Person.MALE:
                remaining = males[key]
            else:
                remaining = females[key]

            #index = 0
            for p2key in remaining:
                #index += 1
                if p1key == p2key:
                    continue
                p2 = self.db.get_person_from_handle(p2key)
                if p2key in self.map:
                    (v,c) = self.map[p2key]
                    if v == p1key:
                        continue

                chance = self.compare_people(p1,p2)
                if chance >= thresh:
                    if p1key in self.map:
                        val = self.map[p1key]
                        if val[1] > chance:
                            self.map[p1key] = (p2key,chance)
                    else:
                        self.map[p1key] = (p2key,chance)

        self.list = sorted(self.map)
        self.length = len(self.list)
        self.progress.close()

    def gen_key(self, val):
        if self.use_soundex:
            try:
                return soundex(val)
            except UnicodeEncodeError:
                return val
        else:
            return val

    def compare_people(self, p1, p2):

        name1 = p1.get_primary_name()
        name2 = p2.get_primary_name()

        chance = self.name_match(name1, name2)
        if chance == -1  :
            return -1

        birth1_ref = p1.get_birth_ref()
        if birth1_ref:
            birth1 = self.db.get_event_from_handle(birth1_ref.ref)
        else:
            birth1 = Event()

        death1_ref = p1.get_death_ref()
        if death1_ref:
            death1 = self.db.get_event_from_handle(death1_ref.ref)
        else:
            death1 = Event()

        birth2_ref = p2.get_birth_ref()
        if birth2_ref:
            birth2 = self.db.get_event_from_handle(birth2_ref.ref)
        else:
            birth2 = Event()

        death2_ref = p2.get_death_ref()
        if death2_ref:
            death2 = self.db.get_event_from_handle(death2_ref.ref)
        else:
            death2 = Event()

        value = self.date_match(birth1.get_date_object(),
                                birth2.get_date_object())
        if value == -1 :
            return -1
        chance += value

        value = self.date_match(death1.get_date_object(),
                                death2.get_date_object())
        if value == -1 :
            return -1
        chance += value

        value = self.place_match(birth1.get_place_handle(),
                                 birth2.get_place_handle())
        if value == -1 :
            return -1
        chance += value

        value = self.place_match(death1.get_place_handle(),
                                 death2.get_place_handle())
        if value == -1 :
            return -1
        chance += value

        ancestors = []
        self.ancestors_of(p1.get_handle(),ancestors)
        if p2.get_handle() in ancestors:
            return -1

        ancestors = []
        self.ancestors_of(p2.get_handle(),ancestors)
        if p1.get_handle() in ancestors:
            return -1

        f1_id = p1.get_main_parents_family_handle()
        f2_id = p2.get_main_parents_family_handle()

        if f1_id and f2_id:
            f1 = self.db.get_family_from_handle(f1_id)
            f2 = self.db.get_family_from_handle(f2_id)
            dad1_id = f1.get_father_handle()
            if dad1_id:
                dad1 = get_name_obj(self.db.get_person_from_handle(dad1_id))
            else:
                dad1 = None
            dad2_id = f2.get_father_handle()
            if dad2_id:
                dad2 = get_name_obj(self.db.get_person_from_handle(dad2_id))
            else:
                dad2 = None

            value = self.name_match(dad1,dad2)

            if value == -1:
                return -1

            chance += value

            mom1_id = f1.get_mother_handle()
            if mom1_id:
                mom1 = get_name_obj(self.db.get_person_from_handle(mom1_id))
            else:
                mom1 = None
            mom2_id = f2.get_mother_handle()
            if mom2_id:
                mom2 = get_name_obj(self.db.get_person_from_handle(mom2_id))
            else:
                mom2 = None

            value = self.name_match(mom1,mom2)
            if value == -1:
                return -1

            chance += value

        for f1_id in p1.get_family_handle_list():
            f1 = self.db.get_family_from_handle(f1_id)
            for f2_id in p2.get_family_handle_list():
                f2 = self.db.get_family_from_handle(f2_id)
                if p1.get_gender() == Person.FEMALE:
                    father1_id = f1.get_father_handle()
                    father2_id = f2.get_father_handle()
                    if father1_id and father2_id:
                        if father1_id == father2_id:
                            chance += 1
                        else:
                            father1 = self.db.get_person_from_handle(father1_id)
                            father2 = self.db.get_person_from_handle(father2_id)
                            fname1 = get_name_obj(father1)
                            fname2 = get_name_obj(father2)
                            value = self.name_match(fname1,fname2)
                            if value != -1:
                                chance += value
                else:
                    mother1_id = f1.get_mother_handle()
                    mother2_id = f2.get_mother_handle()
                    if mother1_id and mother2_id:
                        if mother1_id == mother2_id:
                            chance += 1
                        else:
                            mother1 = self.db.get_person_from_handle(mother1_id)
                            mother2 = self.db.get_person_from_handle(mother2_id)
                            mname1 = get_name_obj(mother1)
                            mname2 = get_name_obj(mother2)
                            value = self.name_match(mname1,mname2)
                            if value != -1:
                                chance += value
        return chance

    def name_compare(self, s1, s2):
        if self.use_soundex:
            try:
                return compare(s1,s2)
            except UnicodeEncodeError:
                return s1 == s2
        else:
            return s1 == s2

    def date_match(self, date1, date2):
        if date1.is_empty() or date2.is_empty():
            return 0
        if date1.is_equal(date2):
            return 1

        if date1.is_compound() or date2.is_compound():
            return self.range_compare(date1,date2)

        if date1.get_year() == date2.get_year():
            if date1.get_month() == date2.get_month():
                return 0.75
            if not date1.get_month_valid() or not date2.get_month_valid():
                return 0.75
            else:
                return -1
        else:
            return -1

    def range_compare(self, date1, date2):
        start_date_1 = date1.get_start_date()[0:3]
        start_date_2 = date2.get_start_date()[0:3]
        stop_date_1 = date1.get_stop_date()[0:3]
        stop_date_2 = date2.get_stop_date()[0:3]
        if date1.is_compound() and date2.is_compound():
            if (start_date_2 <= start_date_1 <= stop_date_2 or
                start_date_1 <= start_date_2 <= stop_date_1 or
                start_date_2 <= stop_date_1 <= stop_date_2 or
                start_date_1 <= stop_date_2 <= stop_date_1):
                return 0.5
            else:
                return -1
        elif date2.is_compound():
            if start_date_2 <= start_date_1 <= stop_date_2:
                return 0.5
            else:
                return -1
        else:
            if start_date_1 <= start_date_2 <= stop_date_1:
                return 0.5
            else:
                return -1

    def name_match(self, name, name1):

        if not name1 or not name:
            return 0

        srn1 = get_surnames(name)
        sfx1 = name.get_suffix()
        srn2 = get_surnames(name1)
        sfx2 = name1.get_suffix()

        if not self.name_compare(srn1,srn2):
            return -1
        if sfx1 != sfx2:
            if sfx1 != "" and sfx2 != "":
                return -1

        if name.get_first_name() == name1.get_first_name():
            return 1
        else:
            list1 = name.get_first_name().split()
            list2 = name1.get_first_name().split()

            if len(list1) < len(list2):
                return self.list_reduce(list1,list2)
            else:
                return self.list_reduce(list2,list1)

    def place_match(self, p1_id, p2_id):
        if p1_id == p2_id:
            return 1

        if not p1_id:
            name1 = ""
        else:
            p1 = self.db.get_place_from_handle(p1_id)
            name1 = p1.get_title()

        if not p2_id:
            name2 = ""
        else:
            p2 = self.db.get_place_from_handle(p2_id)
            name2 = p2.get_title()

        if not (name1 and name2):
            return 0
        if name1 == name2:
            return 1

        list1 = name1.replace(","," ").split()
        list2 = name2.replace(","," ").split()

        value = 0
        for name in list1:
            for name2 in list2:
                if name == name2:
                    value += 0.5
                elif name[0] == name2[0] and self.name_compare(name, name2):
                    value += 0.25
        return min(value,1) if value else -1

    def list_reduce(self, list1, list2):
        value = 0
        for name in list1:
            for name2 in list2:
                if is_initial(name) and name[0] == name2[0]:
                    value += 0.25
                elif is_initial(name2) and name2[0] == name[0]:
                    value += 0.25
                elif name == name2:
                    value += 0.5
                elif name[0] == name2[0] and self.name_compare(name, name2):
                    value += 0.25
        return min(value,1) if value else -1

    def __dummy(self, obj):
        """dummy callback, needed because a shared glade file is used for
        both toplevel windows and all signals must be handled.
        """
        pass
Exemple #26
0
class NotRelated(tool.ActivePersonTool, ManagedWindow):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        tool.ActivePersonTool.__init__(self, dbstate, uistate, options_class,
                                       name)

        if self.fail:  # bug #2709 -- fail if we have no active person
            return

        person_handle = uistate.get_active('Person')
        person = dbstate.db.get_person_from_handle(person_handle)
        self.name = person.get_primary_name().get_regular_name()
        self.title = _('Not related to "%s"') % self.name
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.uistate = uistate
        self.db = dbstate.db

        topDialog = Glade()

        topDialog.connect_signals({
            "destroy_passed_object": self.close,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_event": self.close,
        })

        window = topDialog.toplevel
        title = topDialog.get_object("title")
        self.set_window(window, title, self.title)

        self.tagcombo = topDialog.get_object("tagcombo")
        tagmodel = Gtk.ListStore(str)
        self.tagcombo.set_model(tagmodel)
        self.tagcombo.set_entry_text_column(0)
        tagmodel.append((_('ToDo'), ))
        tagmodel.append((_('NotRelated'), ))
        self.tagcombo.set_sensitive(False)

        self.tagapply = topDialog.get_object("tagapply")
        self.tagapply.set_sensitive(False)
        self.tagapply.connect('clicked', self.applyTagClicked)

        # start the progress indicator
        self.progress = ProgressMeter(self.title,
                                      _('Starting'),
                                      parent=self.window)

        # setup the columns
        self.model = Gtk.TreeStore(
            GObject.TYPE_STRING,  # 0==name
            GObject.TYPE_STRING,  # 1==person gid
            GObject.TYPE_STRING,  # 2==parents
            GObject.TYPE_STRING,  # 3==tags
            GObject.TYPE_STRING)  # 4==family gid (not shown to user)

        # note -- don't assign the model to the tree until it has been populated,
        # otherwise the screen updates are terribly slow while names are appended
        self.treeView = topDialog.get_object("treeview")
        col1 = Gtk.TreeViewColumn(_('Name'), Gtk.CellRendererText(), text=0)
        col2 = Gtk.TreeViewColumn(_('ID'), Gtk.CellRendererText(), text=1)
        col3 = Gtk.TreeViewColumn(_('Parents'), Gtk.CellRendererText(), text=2)
        col4 = Gtk.TreeViewColumn(_('Tags'), Gtk.CellRendererText(), text=3)
        col1.set_resizable(True)
        col2.set_resizable(True)
        col3.set_resizable(True)
        col4.set_resizable(True)
        col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col1.set_sort_column_id(0)
        #        col2.set_sort_column_id(1)
        #        col3.set_sort_column_id(2)
        col4.set_sort_column_id(3)
        self.treeView.append_column(col1)
        self.treeView.append_column(col2)
        self.treeView.append_column(col3)
        self.treeView.append_column(col4)
        self.treeSelection = self.treeView.get_selection()
        self.treeSelection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.treeSelection.set_select_function(self.selectIsAllowed, None)
        self.treeSelection.connect('changed', self.rowSelectionChanged)
        self.treeView.connect('row-activated', self.rowActivated)

        # initialize a few variables we're going to need
        self.numberOfPeopleInDatabase = self.db.get_number_of_people()
        self.numberOfRelatedPeople = 0
        self.numberOfUnrelatedPeople = 0

        # create the sets used to track related and unrelated people
        self.handlesOfPeopleToBeProcessed = set()
        self.handlesOfPeopleAlreadyProcessed = set()
        self.handlesOfPeopleNotRelated = set()

        # build a set of all people related to the selected person
        self.handlesOfPeopleToBeProcessed.add(person.get_handle())
        self.findRelatedPeople()

        # now that we have our list of related people, find everyone
        # in the database who isn't on our list
        self.findUnrelatedPeople()

        # populate the treeview model with the names of unrelated people
        if self.numberOfUnrelatedPeople == 0:
            # feature request 2356: avoid genitive form
            title.set_text(
                _('Everyone in the database is related to %s') % self.name)
        else:
            self.populateModel()
            self.model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
            self.treeView.set_model(self.model)
            #            self.treeView.set_row_separator_func(self.iterIsSeparator, None)
            self.treeView.expand_all()

        # done searching through the database, so close the progress bar
        self.progress.close()

        self.show()

    def iterIsSeparator(self, model, iter):
        # return True only if the row is to be treated as a separator
        if self.model.get_value(iter, 1) == '':  # does the row have a GID?
            return True
        return False

    def selectIsAllowed(self, selection, model, path, isSelected, userData):
        # return True/False depending on if the row being selected is a leaf node
        iter = self.model.get_iter(path)
        if self.model.get_value(iter, 1) == '':  # does the row have a GID?
            return False
        return True

    def rowSelectionChanged(self, selection):
        state = selection.count_selected_rows() > 0
        self.tagcombo.set_sensitive(state)
        self.tagapply.set_sensitive(state)

    def rowActivated(self, treeView, path, column):
        # first we need to check that the row corresponds to a person
        iter = self.model.get_iter(path)
        personGid = self.model.get_value(iter, 1)
        familyGid = self.model.get_value(iter, 4)

        if familyGid != '':  # do we have a family?
            # get the parent family for this person
            family = self.db.get_family_from_gramps_id(familyGid)
            if family:
                try:
                    EditFamily(self.dbstate, self.uistate, [], family)
                except WindowActiveError:
                    pass

        elif personGid != '':  # do we have a person?
            # get the person that corresponds to this GID
            person = self.db.get_person_from_gramps_id(personGid)
            if person:
                try:
                    EditPerson(self.dbstate, self.uistate, [], person)
                except WindowActiveError:
                    pass

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC)

    def applyTagClicked(self, button):
        progress = None
        rows = self.treeSelection.count_selected_rows()
        tag_name = str(self.tagcombo.get_active_text())

        # start the db transaction
        with DbTxn("Tag not related", self.db) as transaction:

            tag = self.db.get_tag_from_name(tag_name)
            if not tag:
                # create the tag if it doesn't already exist
                tag = Tag()
                tag.set_name(tag_name)
                tag.set_priority(self.db.get_number_of_tags())
                tag_handle = self.db.add_tag(tag, transaction)
            else:
                tag_handle = tag.get_handle()

            # if more than 1 person is selected, use a progress indicator
            if rows > 1:
                progress = ProgressMeter(self.title,
                                         _('Starting'),
                                         parent=self.window)
                progress.set_pass(
                    # translators: leave all/any {...} untranslated
                    #TRANS: no singular form needed, as rows is always > 1
                    ngettext("Setting tag for {number_of} person",
                             "Setting tag for {number_of} people",
                             rows).format(number_of=rows),
                    rows)

            # iterate through all of the selected rows
            (model, paths) = self.treeSelection.get_selected_rows()

            for path in paths:
                if progress:
                    progress.step()

                # for the current row, get the GID and the person from the database
                iter = self.model.get_iter(path)
                personGid = self.model.get_value(iter, 1)
                person = self.db.get_person_from_gramps_id(personGid)

                # add the tag to the person
                person.add_tag(tag_handle)

                # save this change
                self.db.commit_person(person, transaction)

        # refresh the tags column
        self.treeView.set_model(None)
        for path in paths:
            iter = self.model.get_iter(path)
            personGid = self.model.get_value(iter, 1)
            person = self.db.get_person_from_gramps_id(personGid)
            self.model.set_value(iter, 3, self.get_tag_list(person))
        self.treeView.set_model(self.model)
        self.treeView.expand_all()

        if progress:
            progress.close()

    def findRelatedPeople(self):

        self.progress.set_pass(
            # translators: leave all/any {...} untranslated
            #TRANS: No singular form is needed.
            ngettext("Finding relationships between {number_of} person",
                     "Finding relationships between {number_of} people",
                     self.numberOfPeopleInDatabase).format(
                         number_of=self.numberOfPeopleInDatabase),
            self.numberOfPeopleInDatabase)

        # as long as we have people we haven't processed yet, keep looping
        while len(self.handlesOfPeopleToBeProcessed) > 0:
            handle = self.handlesOfPeopleToBeProcessed.pop()

            ### DEBUG DEBUG DEBUG
            #            if len(self.handlesOfPeopleAlreadyProcessed) > 50:
            #                break
            ###

            # see if we've already processed this person
            if handle in self.handlesOfPeopleAlreadyProcessed:
                continue

            person = self.db.get_person_from_handle(handle)

            # if we get here, then we're dealing with someone new
            self.progress.step()

            # remember that we've now seen this person
            self.handlesOfPeopleAlreadyProcessed.add(handle)

            # we have 4 things to do:  find (1) spouses, (2) parents, siblings(3), and (4) children

            # step 1 -- spouses
            for familyHandle in person.get_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                spouseHandle = utils.find_spouse(person, family)
                if spouseHandle and \
                  spouseHandle not in self.handlesOfPeopleAlreadyProcessed:
                    self.handlesOfPeopleToBeProcessed.add(spouseHandle)

            # step 2 -- parents
            for familyHandle in person.get_parent_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                fatherHandle = family.get_father_handle()
                motherHandle = family.get_mother_handle()
                if fatherHandle and \
                  fatherHandle not in self.handlesOfPeopleAlreadyProcessed:
                    self.handlesOfPeopleToBeProcessed.add(fatherHandle)
                if motherHandle and \
                  motherHandle not in self.handlesOfPeopleAlreadyProcessed:
                    self.handlesOfPeopleToBeProcessed.add(motherHandle)

            # step 3 -- siblings
            for familyHandle in person.get_parent_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                for childRef in family.get_child_ref_list():
                    childHandle = childRef.ref
                    if childHandle and \
                      childHandle not in self.handlesOfPeopleAlreadyProcessed:
                        self.handlesOfPeopleToBeProcessed.add(childHandle)

            # step 4 -- children
            for familyHandle in person.get_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                for childRef in family.get_child_ref_list():
                    childHandle = childRef.ref
                    if childHandle and \
                      childHandle not in self.handlesOfPeopleAlreadyProcessed:
                        self.handlesOfPeopleToBeProcessed.add(childHandle)

    def findUnrelatedPeople(self):

        # update our numbers
        self.numberOfRelatedPeople = len(self.handlesOfPeopleAlreadyProcessed)
        self.numberOfUnrelatedPeople = (self.numberOfPeopleInDatabase -
                                        self.numberOfRelatedPeople)

        if self.numberOfUnrelatedPeople > 0:
            # we have at least 1 "unrelated" person to find

            self.progress.set_pass(
                # translators: leave all/any {...} untranslated
                ngettext("Looking for {number_of} person",
                         "Looking for {number_of} people",
                         self.numberOfUnrelatedPeople).format(
                             number_of=self.numberOfUnrelatedPeople),
                self.numberOfPeopleInDatabase)

            # loop through everyone in the database
            for handle in self.db.iter_person_handles():

                self.progress.step()

                # if this person is related, then skip to the next one
                if handle in self.handlesOfPeopleAlreadyProcessed:
                    continue

### DEBUG DEBUG DEBUG
#                if len(self.handlesOfPeopleNotRelated) > 10:
#                    break
###

# if we get here, we have someone who is "not related"
                self.handlesOfPeopleNotRelated.add(handle)

    def populateModel(self):

        self.progress.set_pass(
            # translators: leave all/any {...} untranslated
            ngettext("Looking up the name of {number_of} person",
                     "Looking up the names of {number_of} people",
                     self.numberOfUnrelatedPeople).format(
                         number_of=self.numberOfUnrelatedPeople),
            self.numberOfUnrelatedPeople)

        # loop through the entire list of unrelated people
        for handle in self.handlesOfPeopleNotRelated:
            self.progress.step()
            person = self.db.get_person_from_handle(handle)
            primaryname = person.get_primary_name()
            surname = primaryname.get_surname()
            name = primaryname.get_name()
            gid = person.get_gramps_id()

            # Retrieve the sorted tag list
            tag_list = self.get_tag_list(person)

            # find the names of the parents
            familygid = ''
            parentNames = ''
            parentFamilyHandle = person.get_main_parents_family_handle()
            if parentFamilyHandle:
                parentFamily = self.db.get_family_from_handle(
                    parentFamilyHandle)
                familygid = parentFamily.get_gramps_id()
                fatherName = None
                motherName = None
                fatherHandle = parentFamily.get_father_handle()
                if fatherHandle:
                    father = self.db.get_person_from_handle(fatherHandle)
                    fatherName = father.get_primary_name().get_first_name()
                motherHandle = parentFamily.get_mother_handle()
                if motherHandle:
                    mother = self.db.get_person_from_handle(motherHandle)
                    motherName = mother.get_primary_name().get_first_name()

                # now that we have the names, come up with a label we can use
                if fatherName:
                    parentNames += fatherName
                if fatherName and motherName:
                    parentNames += ' & '
                if motherName:
                    parentNames += motherName

            # get the surname node (or create it if it doesn't exist)

            # start with the root
            iter = self.model.get_iter_first()
            # look for a node with a matching surname
            while iter:
                if self.model.get_value(iter, 0) == surname:
                    break
                iter = self.model.iter_next(iter)

            # if we don't have a valid iter, then create a new top-level node
            if not iter:
                iter = self.model.append(None, [surname, '', '', '', ''])

            # finally, we now get to add this person to the model
            self.model.append(iter,
                              [name, gid, parentNames, tag_list, familygid])

    def build_menu_names(self, obj):
        return (self.title, None)

    def get_tag_list(self, person):
        """
        Return a sorted list of tag names for the given person.
        """
        tags = []
        for handle in person.get_tag_list():
            tag = self.db.get_tag_from_handle(handle)
            tags.append(tag.get_name())
        tags.sort(key=glocale.sort_key)
        return ', '.join(tags)
Exemple #27
0
class ReorderIds(tool.BatchTool):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        db = dbstate.db
        self.uistate = uistate
        if uistate:
            self.progress = ProgressMeter(
                _('Reordering Gramps IDs'), '', parent=uistate.window)
        else:
            print(_("Reordering Gramps IDs..."))

        with DbTxn(_("Reorder Gramps IDs"), db, batch=True) as self.trans:
            db.disable_signals()

            if uistate:
                self.progress.set_pass(_('Reordering People IDs'),
                                       db.get_number_of_people())
            self.reorder(Person,
                         db.get_person_from_gramps_id,
                         db.get_person_from_handle,
                         db.find_next_person_gramps_id,
                         db.person_map,
                         db.commit_person,
                         db.person_prefix)

            if uistate:
                self.progress.set_pass(_('Reordering Family IDs'),
                                       db.get_number_of_families())
            self.reorder(Family,
                         db.get_family_from_gramps_id,
                         db.get_family_from_handle,
                         db.find_next_family_gramps_id,
                         db.family_map,
                         db.commit_family,
                         db.family_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Event IDs'),
                                       db.get_number_of_events())
            self.reorder(Event,
                         db.get_event_from_gramps_id,
                         db.get_event_from_handle,
                         db.find_next_event_gramps_id,
                         db.event_map,
                         db.commit_event,
                         db.event_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Media Object IDs'),
                                       db.get_number_of_media())
            self.reorder(Media,
                         db.get_media_from_gramps_id,
                         db.get_media_from_handle,
                         db.find_next_media_gramps_id,
                         db.media_map,
                         db.commit_media,
                         db.media_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Source IDs'),
                                       db.get_number_of_sources())
            self.reorder(Source,
                         db.get_source_from_gramps_id,
                         db.get_source_from_handle,
                         db.find_next_source_gramps_id,
                         db.source_map,
                         db.commit_source,
                         db.source_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Citation IDs'),
                                       db.get_number_of_citations())
            self.reorder(Citation,
                         db.get_citation_from_gramps_id,
                         db.get_citation_from_handle,
                         db.find_next_citation_gramps_id,
                         db.citation_map,
                         db.commit_citation,
                         db.citation_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Place IDs'),
                                       db.get_number_of_places())
            self.reorder(Place,
                         db.get_place_from_gramps_id,
                         db.get_place_from_handle,
                         db.find_next_place_gramps_id,
                         db.place_map,
                         db.commit_place,
                         db.place_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Repository IDs'),
                                       db.get_number_of_repositories())
            self.reorder(Repository,
                         db.get_repository_from_gramps_id,
                         db.get_repository_from_handle,
                         db.find_next_repository_gramps_id,
                         db.repository_map,
                         db.commit_repository,
                         db.repository_prefix)
    #add reorder notes ID
            if uistate:
                self.progress.set_pass(_('Reordering Note IDs'),
                                       db.get_number_of_notes())
            self.reorder(Note,
                         db.get_note_from_gramps_id,
                         db.get_note_from_handle,
                         db.find_next_note_gramps_id,
                         db.note_map,
                         db.commit_note,
                         db.note_prefix)
            if uistate:
                self.progress.close()
            else:
                print(_("Done."))

        db.enable_signals()
        db.request_rebuild()

    def reorder(self, class_type, find_from_id, find_from_handle,
                find_next_id, table, commit, prefix):
        dups = []
        newids = {}

        formatmatch = _parseformat.match(prefix)

        for handle in list(table.keys()):
            if self.uistate:
                self.progress.step()

            sdata = table[handle]

            obj = class_type()
            obj.unserialize(sdata)
            gramps_id = obj.get_gramps_id()
            # attempt to extract integer, if we can't, treat it as a
            # duplicate

            try:
                match = _findint.match(gramps_id)
                if match:
                    # get the integer, build the new handle. Make sure it
                    # hasn't already been chosen. If it has, put this
                    # in the duplicate handle list

                    index = match.groups()[0]

                    if formatmatch:
                        if int(index) > int("9" * int(formatmatch.groups()[0])):
                            newgramps_id = find_next_id()
                        else:
                            newgramps_id = prefix % int(index)
                    else:
                        # the prefix does not contain a number after %, eg I%d
                        newgramps_id = prefix % int(index)

                    if newgramps_id == gramps_id:
                        if newgramps_id in newids:
                            dups.append(obj.get_handle())
                        else:
                            newids[newgramps_id] = gramps_id
                    elif find_from_id(newgramps_id) is not None:
                        dups.append(obj.get_handle())
                    else:
                        obj.set_gramps_id(newgramps_id)
                        commit(obj, self.trans)
                        newids[newgramps_id] = gramps_id
                else:
                    dups.append(handle)
            except:
                dups.append(handle)

        # go through the duplicates, looking for the first available
        # handle that matches the new scheme.

        if self.uistate:
            self.progress.set_pass(_('Finding and assigning unused IDs'),
                                   len(dups))
        for handle in dups:
            if self.uistate:
                self.progress.step()
            obj = find_from_handle(handle)
            obj.set_gramps_id(find_next_id())
            commit(obj, self.trans)
Exemple #28
0
class DisplayChart(ManagedWindow):
    def __init__(self, dbstate, uistate, people_list, track):
        self.dbstate = dbstate
        self.uistate = uistate

        ManagedWindow.__init__(self, uistate, track, self)

        self.db = dbstate.db
        self.my_list = people_list
        self.row_data = []
        self.save_form = None

        self.topDialog = Glade()
        self.topDialog.connect_signals(
            {
                "on_write_table": self.on_write_table,
                "destroy_passed_object": self.close,
                "on_help_clicked": self.on_help_clicked,
                "on_apply_clicked": self.__dummy,
                "on_editor_clicked": self.__dummy,
            }
        )

        window = self.topDialog.toplevel
        self.set_window(window, self.topDialog.get_object("title"), _("Event Comparison Results"))

        self.eventlist = self.topDialog.get_object("treeview")
        self.sort = Sort(self.db)
        self.my_list.sort(key=self.sort.by_last_name_key)

        self.event_titles = self.make_event_titles()

        self.table_titles = [_("Person"), _("ID")]
        for event_name in self.event_titles:
            self.table_titles.append(_("%(event_name)s Date") % {"event_name": event_name})
            self.table_titles.append("sort")  # This won't be shown in a tree
            self.table_titles.append(_("%(event_name)s Place") % {"event_name": event_name})

        self.build_row_data()
        self.draw_display()
        self.show()

    def __dummy(self, obj):
        """dummy callback, needed because widget is in same glade file
        as another widget, so callbacks must be defined to avoid warnings.
        """
        pass

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def build_menu_names(self, obj):
        return (_("Event Comparison Results"), None)

    def draw_display(self):

        model_index = 0
        tree_index = 0
        mylist = []
        renderer = Gtk.CellRendererText()
        for title in self.table_titles:
            mylist.append(str)
            if title == "sort":
                # This will override the previously defined column
                self.eventlist.get_column(tree_index - 1).set_sort_column_id(model_index)
            else:
                column = Gtk.TreeViewColumn(title, renderer, text=model_index)
                column.set_sort_column_id(model_index)
                self.eventlist.append_column(column)
                # This one numbers the tree columns: increment on new column
                tree_index += 1
            # This one numbers the model columns: always increment
            model_index += 1

        model = Gtk.ListStore(*mylist)
        self.eventlist.set_model(model)

        self.progress_bar.set_pass(_("Building display"), len(self.row_data))
        for data in self.row_data:
            model.append(row=list(data))
            self.progress_bar.step()
        self.progress_bar.close()

    def build_row_data(self):
        self.progress_bar = ProgressMeter(_("Comparing Events"), "", parent=self.window)
        self.progress_bar.set_pass(_("Building data"), len(self.my_list))
        for individual_id in self.my_list:
            individual = self.db.get_person_from_handle(individual_id)
            name = individual.get_primary_name().get_name()
            gid = individual.get_gramps_id()

            the_map = defaultdict(list)
            for ievent_ref in individual.get_event_ref_list():
                ievent = self.db.get_event_from_handle(ievent_ref.ref)
                event_name = str(ievent.get_type())
                the_map[event_name].append(ievent_ref.ref)

            first = True
            done = False
            while not done:
                added = False
                tlist = [name, gid] if first else ["", ""]

                for ename in self.event_titles:
                    if ename in the_map and len(the_map[ename]) > 0:
                        event_handle = the_map[ename][0]
                        del the_map[ename][0]
                        date = place = ""

                        if event_handle:
                            event = self.db.get_event_from_handle(event_handle)
                            date = get_date(event)
                            sortdate = "%09d" % (event.get_date_object().get_sort_value())
                            place_handle = event.get_place_handle()
                            if place_handle:
                                place = self.db.get_place_from_handle(place_handle).get_title()
                        tlist += [date, sortdate, place]
                        added = True
                    else:
                        tlist += [""] * 3

                if first:
                    first = False
                    self.row_data.append(tlist)
                elif not added:
                    done = True
                else:
                    self.row_data.append(tlist)
            self.progress_bar.step()

    def make_event_titles(self):
        """
        Create the list of unique event types, along with the person's
        name, birth, and death.
        This should be the column titles of the report.
        """
        the_map = defaultdict(int)
        for individual_id in self.my_list:
            individual = self.db.get_person_from_handle(individual_id)
            for event_ref in individual.get_event_ref_list():
                event = self.db.get_event_from_handle(event_ref.ref)
                name = str(event.get_type())
                if not name:
                    break
                the_map[name] += 1

        unsort_list = sorted([(d, k) for k, d in the_map.items()], key=lambda x: x[0], reverse=True)

        sort_list = [item[1] for item in unsort_list]
        ## Presently there's no Birth and Death. Instead there's Birth Date and
        ## Birth Place, as well as Death Date and Death Place.
        ##         # Move birth and death to the begining of the list
        ##         if _("Death") in the_map:
        ##             sort_list.remove(_("Death"))
        ##             sort_list = [_("Death")] + sort_list

        ##         if _("Birth") in the_map:
        ##             sort_list.remove(_("Birth"))
        ##             sort_list = [_("Birth")] + sort_list

        return sort_list

    def on_write_table(self, obj):
        f = Gtk.FileChooserDialog(
            _("Select filename"),
            parent=self.window,
            action=Gtk.FileChooserAction.SAVE,
            buttons=(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Save"), Gtk.ResponseType.OK),
        )

        f.set_current_folder(get_curr_dir())
        status = f.run()
        f.hide()

        if status == Gtk.ResponseType.OK:
            name = conv_to_unicode(f.get_filename())
            doc = ODSTab(len(self.row_data))
            doc.creator(self.db.get_researcher().get_name())

            spreadsheet = TableReport(name, doc)

            new_titles = []
            skip_columns = []
            index = 0
            for title in self.table_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.row_data:
                spreadsheet.set_row(index % 2)
                index += 1
                spreadsheet.write_table_data(top, skip_columns)

            spreadsheet.finalize()
        f.destroy()
Exemple #29
0
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
    """ Class for Reodering Gramps ID Tool """
    xobjects = (('person', 'people'), ('family', 'families'),
                ('event', 'events'), ('place', 'places'),
                ('source', 'sources'), ('citation', 'citations'),
                ('repository', 'repositories'), ('media', 'media'), ('note',
                                                                     'notes'))

    def build_menu_names_(self, widget=None):
        """ The menu name """
        return (_('Main window'), _("Reorder Gramps IDs"))

    def __init__(self, dbstate, user, options_class, name, callback=None):
        self.uistate = user.uistate
        self.dbstate = dbstate.db

        if self.uistate:
            tool.BatchTool.__init__(self, dbstate, user, options_class, name)
            if self.fail:
                return  # user denied to modify Gramps IDs

        ManagedWindow.__init__(self, self.uistate, [], self.__class__)
        if not self.uistate:
            UpdateCallback.__init__(self, user.callback)

        self.object_status = True
        self.change_status = False
        self.start_zero = True
        self.step_cnt, self.step_list = 0, ['1', '2', '5', '10']
        self.keep_status = True

        self.obj_values = {}  # enable access to all internal values
        self.active_entries, self.format_entries = {}, {}
        self.change_entries = {}
        self.start_entries, self.step_entries = {}, {}
        self.keep_entries = {}

        self.prim_methods, self.obj_methods = {}, {}
        for prim_obj, prim_objs in self.xobjects:
            class_type = prim_obj.title()
            iter_handles = "self.dbstate.iter_%s_handles" % prim_obj
            get_number_obj = "self.dbstate.get_number_of_%s" % prim_objs
            prefix_fmt = "self.dbstate.%s_prefix" % prim_obj
            get_from_id = "self.dbstate.get_%s_from_gramps_id" % prim_obj
            get_from_handle = "self.dbstate.get_%s_from_handle" % prim_obj
            next_from_id = "self.dbstate.find_next_%s_gramps_id" % prim_obj
            commit = "self.dbstate.commit_%s" % prim_obj

            self.prim_methods[prim_obj] = (eval(prefix_fmt),
                                           eval(get_number_obj)(),
                                           eval(next_from_id)())
            self.obj_methods[prim_obj] = (eval(class_type), eval(iter_handles),
                                          eval(commit), eval(get_from_id),
                                          eval(get_from_handle),
                                          eval(next_from_id))

            object_fmt, quant_id, next_id = self.prim_methods[prim_obj]

            obj_value = ReorderEntry(object_fmt, quant_id, next_id)
            self.obj_values[prim_obj] = obj_value

        if self.uistate:
            self._display()
        else:
            self._execute()

    def __on_object_button_clicked(self, widget=None):
        """ compute all primary objects and toggle the 'Active' attribute """
        self.object_status = not self.object_status

        for prim_obj, tmp in self.xobjects:
            obj = self.top.get_object('%s_active' % prim_obj)
            obj.set_active(self.object_status)

    def __on_object_button_toggled(self, widget):
        """ compute the primary object and toggle the 'Sensitive' attribute """
        obj_state = widget.get_active()
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]

        self.active_entries[obj_name].set_val(obj_state)

        for obj_entry in ['actual', 'quant', 'format', 'change']:
            obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
            obj.set_sensitive(obj_state)

        for obj_entry in ['start', 'step', 'keep']:
            obj = self.top.get_object('%s_change' % obj_name)
            if obj.get_active():
                obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
                obj.set_sensitive(obj_state)

    def __on_format_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Format' scheme of identifiers """
        for prim_obj, tmp in self.xobjects:
            obj_format = self.top.get_object('%s_format' % prim_obj)
            if not obj_format.get_sensitive():
                continue

            obj_fmt = self.obj_values[prim_obj].res_fmt()
            self.format_entries[prim_obj].force_value(obj_fmt)
            if self.start_zero:
                obj_id = self.obj_values[prim_obj].zero_id()
            else:
                obj_id = self.obj_values[prim_obj].last_id()
            self.start_entries[prim_obj].force_value(obj_id)

    def __on_change_button_clicked(self, widget=None):
        """ compute all primary objects and toggle the 'Change' attribute """
        self.change_status = not self.change_status

        for prim_obj, tmp in self.xobjects:
            obj_change = self.top.get_object('%s_change' % prim_obj)
            if not obj_change.get_sensitive():
                continue

            self.change_entries[prim_obj].set_val(self.change_status)
            obj_change.set_active(self.change_status)

    def __on_change_button_toggled(self, widget):
        """ compute the primary object and toggle the 'Sensitive' attribute """
        obj_state = widget.get_active()
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]

        for obj_entry in ['start', 'step', 'keep']:
            obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
            if obj_entry == 'keep':
                if self.obj_values[obj_name].stored_prefix != \
                   self.obj_values[obj_name].object_prefix:
                    self.keep_entries[obj_name].set_val(False)
                else:
                    obj.set_active(obj_state)
                    self.keep_entries[obj_name].set_val(obj_state)
            obj.set_sensitive(obj_state)

    def __on_start_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Start' values of identifiers """
        self.start_zero = not self.start_zero

        for prim_obj, tmp in self.xobjects:
            obj = self.top.get_object('%s_start' % prim_obj)
            if not obj.get_sensitive():
                continue

            if self.start_zero:
                obj_id = self.obj_values[prim_obj].zero_id()
            else:
                obj_id = self.obj_values[prim_obj].next_id()
            self.start_entries[prim_obj].force_value(obj_id)

    def __on_step_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Step' width of identifiers """
        self.step_cnt = self.step_cnt + 1 if self.step_cnt < 3 else 0

        for prim_obj, tmp in self.xobjects:
            obj = self.top.get_object('%s_step' % prim_obj)
            if not obj.get_sensitive():
                continue

            step_val = self.step_list[self.step_cnt]
            self.step_entries[prim_obj].force_value(step_val)

    def __on_keep_button_clicked(self, widget=None):
        """ compute the primary object and toggle the 'Active' attribute """
        self.keep_status = not self.keep_status

        for prim_obj, tmp in self.xobjects:
            obj = self.top.get_object('%s_change' % prim_obj)
            if not obj.get_active():
                continue

            obj = self.top.get_object('%s_keep' % prim_obj)
            obj.set_active(self.keep_status)
            self.keep_entries[prim_obj].set_val(self.keep_status)

    def __on_format_entry_keyrelease(self, widget, event, data=None):
        """ activated on all return's of an entry """
        if event.keyval in [Gdk.KEY_Return]:
            obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
            obj_fmt = self.format_entries[obj_name].get_val()
            self.format_entries[obj_name].force_value(obj_fmt)
            self.start_entries[obj_name].update()

            obj_change = self.top.get_object('%s_change' % obj_name)
            obj_change.grab_focus()

        return False

    def __on_format_entry_focusout(self, widget, event, data=None):
        """ activated on all focus out of an entry """
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
        obj_fmt = self.format_entries[obj_name].get_val()

        self.format_entries[obj_name].set_val(obj_fmt)
        self.start_entries[obj_name].update()

        return False

    def __on_start_entry_focusout(self, widget, event, data=None):
        """ activated on all focus out of an entry """
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
        self.start_entries[obj_name].update()

        return False

    def __on_ok_button_clicked(self, widget=None):
        """ execute the reodering and close """
        self._execute()
        self._update()

        self.close()

    def __on_cancel_button_clicked(self, widget=None):
        """ cancel the reodering and close """
        self.close()

    def __on_help_button_clicked(self, widget=None):
        """ display the relevant portion of Gramps manual """
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def _display(self):
        """ organize Glade 'Reorder IDs' window """

        # get the main window from glade
        self.top = Glade(toplevel="reorder-ids")
        window = self.top.toplevel

        # set gramps style title for the window
        self.set_window(window, self.top.get_object("title"), \
                        _("Reorder Gramps IDs"))

        # connect signals
        self.top.connect_signals({
            "on_object_button_clicked":
            self.__on_object_button_clicked,
            "on_object_button_toggled":
            self.__on_object_button_toggled,
            "on_format_button_clicked":
            self.__on_format_button_clicked,
            "on_start_button_clicked":
            self.__on_start_button_clicked,
            "on_step_button_clicked":
            self.__on_step_button_clicked,
            "on_keep_button_clicked":
            self.__on_keep_button_clicked,
            "on_change_button_clicked":
            self.__on_change_button_clicked,
            "on_change_button_toggled":
            self.__on_change_button_toggled,
            "on_format_entry_keyrelease":
            self.__on_format_entry_keyrelease,
            "on_format_entry_focusout":
            self.__on_format_entry_focusout,
            "on_start_entry_focusout":
            self.__on_start_entry_focusout,
            "on_help_button_clicked":
            self.__on_help_button_clicked,
            "on_cancel_button_clicked":
            self.__on_cancel_button_clicked,
            "on_ok_button_clicked":
            self.__on_ok_button_clicked
        })

        # Calculate all entries and update Glade window
        for prim_obj, tmp in self.xobjects:
            # populate Object, Actual & Quantity fields with values
            obj_active = self.top.get_object('%s_active' % prim_obj)
            self.active_entries[prim_obj] = MonitoredCheckbox(
                obj_active, obj_active, self.obj_values[prim_obj].set_active,
                self.obj_values[prim_obj].get_active)
            obj_actual = self.top.get_object('%s_actual' % prim_obj)
            obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id())
            obj_quant = self.top.get_object('%s_quant' % prim_obj)
            obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id))

            # connect/populate Format, Start, Step, Keep & Change fields with GTK/values
            obj_format = self.top.get_object('%s_format' % prim_obj)
            self.format_entries[prim_obj] = MonitoredEntry(
                obj_format, self.obj_values[prim_obj].set_fmt,
                self.obj_values[prim_obj].get_fmt)
            obj_change = self.top.get_object('%s_change' % prim_obj)
            self.change_entries[prim_obj] = MonitoredCheckbox(
                obj_change, obj_change, self.obj_values[prim_obj].set_change,
                self.obj_values[prim_obj].get_change)
            obj_start = self.top.get_object('%s_start' % prim_obj)
            self.start_entries[prim_obj] = MonitoredEntry(
                obj_start, self.obj_values[prim_obj].set_id,
                self.obj_values[prim_obj].get_id)
            obj_step = self.top.get_object('%s_step' % prim_obj)
            self.step_entries[prim_obj] = MonitoredEntry(
                obj_step,
                self.obj_values[prim_obj].set_step,
                self.obj_values[prim_obj].get_step,
                changed=self.obj_values[prim_obj].change_step)
            obj_keep = self.top.get_object('%s_keep' % prim_obj)
            self.keep_entries[prim_obj] = MonitoredCheckbox(
                obj_keep,
                obj_keep,
                self.obj_values[prim_obj].set_keep,
                self.obj_values[prim_obj].get_keep,
                readonly=True)

        # fetch the popup menu
        self.menu = self.top.get_object("popup_menu")

        # ok, let's see what we've done
        self.show()

    def _update(self):
        """ store changed objects formats in DB """

        update = False
        for prim_obj, tmp in self.xobjects:
            obj_value = self.obj_values[prim_obj]
            if obj_value.object_fmt != obj_value.stored_fmt:
                prefix = obj_value.object_prefix.lower()
                constant = 'preferences.%sprefix' % prefix
                config.set(constant, obj_value.object_fmt)
                update = True

        if update:
            config.save()
            self.dbstate.set_prefixes(config.get('preferences.iprefix'),
                                      config.get('preferences.oprefix'),
                                      config.get('preferences.fprefix'),
                                      config.get('preferences.sprefix'),
                                      config.get('preferences.cprefix'),
                                      config.get('preferences.pprefix'),
                                      config.get('preferences.eprefix'),
                                      config.get('preferences.rprefix'),
                                      config.get('preferences.nprefix'))

    def _execute(self):
        """ execute all primary objects and reorder if neccessary """

        # Update progress calculation
        if self.uistate:
            self.progress = ProgressMeter(_('Reorder Gramps IDs'), '')
        else:
            total_objs = 0
            for prim_obj, tmp in self.xobjects:
                if self.obj_values[prim_obj].active_obj:
                    total_objs += self.obj_values[prim_obj].quant_id
            self.set_total(total_objs)

        # Update database
        self.dbstate.disable_signals()
        for prim_obj, prim_objs in self.xobjects:
            with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.dbstate, batch=True) \
            as self.trans:
                if self.obj_values[prim_obj].active_obj:
                    if self.uistate:
                        self.progress.set_pass(_('Reorder %s IDs ...') % \
                                               _(prim_objs.title()), \
                                               self.obj_values[prim_obj].quant_id)
                    # Process reordering
                    self._reorder(prim_obj)

        self.dbstate.enable_signals()
        self.dbstate.request_rebuild()

        # Update progress calculation
        if self.uistate:
            self.progress.close()
        else:
            print('\nDone.')

    # finds integer portion in a GrampsID
    _findint = re.compile('^[^\d]*(\d+)[^\d]*')

    def _reorder(self, prim_obj):
        """ reorders all selected objects with a (new) style, start & step """

        dup_ids = []  # list of duplicate identifiers
        new_ids = {}  # list of new identifiers

        class_type, iter_handles, commit, get_from_id, get_from_handle, next_from_id = \
            self.obj_methods[prim_obj]

        prefix_fmt = self.obj_values[prim_obj].get_fmt()
        prefix = prefix_fmt.split('%', 1)[0]
        new_id = self.obj_values[prim_obj].get_id()
        keep_fmt = self.obj_values[prim_obj].get_keep()
        change = self.obj_values[prim_obj].get_change()

        formatmatch = _parseformat.match(prefix_fmt)
        index_max = int("9" * int(formatmatch.groups()[0]))

        for handle in iter_handles():
            # Update progress
            if self.uistate:
                self.progress.step()
            else:
                self.update()

            # extract basic data out of the database
            obj = get_from_handle(handle)

            act_id = obj.get_gramps_id()
            if change:
                # update the defined ID numbers into objects under consideration
                # of keeping ID if format not matches prefix
                # (implication logical boolean operator below)
                if act_id.startswith(prefix) or not keep_fmt:
                    obj.set_gramps_id(new_id)
                    commit(obj, self.trans)
                    new_id = self.obj_values[prim_obj].succ_id()
            else:
                # attempt to extract integer - if we can't, treat it as a duplicate
                try:
                    match = _findint.match(act_id)
                    if match:
                        # get the integer, build the new handle. Make sure it
                        # hasn't already been chosen. If it has, put this
                        # in the duplicate handle list

                        index = int(match.groups()[0])
                        if formatmatch:
                            if index > index_max:
                                new_id = next_from_id()
                            else:
                                new_id = prefix_fmt % index
                        else:
                            # prefix_fmt does not contain a number after %, eg I%d
                            new_id = prefix_fmt % index

                        if new_id == act_id:
                            if new_id in new_ids:
                                dup_ids.append(obj.get_handle())
                            else:
                                new_ids[new_id] = act_id
                        elif get_from_id(new_id) is not None:
                            dup_ids.append(obj.get_handle())
                        else:
                            obj.set_id(new_id)
                            commit(obj, self.trans)
                            new_ids[new_id] = act_id
                    else:
                        dup_ids.append(handle)
                except:
                    dup_ids.append(handle)

        # go through the duplicates, looking for the first available
        # handle that matches the new scheme.
        if dup_ids:
            if self.uistate:
                self.progress.set_pass(_('Finding and assigning unused IDs.'),
                                       len(dup_ids))
            for handle in dup_ids:
                obj = get_from_handle(handle)
                obj.set_gramps_id(next_from_id())
                commit(obj, self.trans)
Exemple #30
0
class FindLoop(ManagedWindow):
    """
    Find loops in the family tree.
    """
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        self.title = _('Find database loop')
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.uistate = uistate
        #self.db = CacheProxyDb(dbstate.db)
        self.db = dbstate.db

        top_dialog = Glade()

        top_dialog.connect_signals({
            "destroy_passed_object" : self.close,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_event"       : self.close,
        })

        window = top_dialog.toplevel
        title = top_dialog.get_object("title")
        self.set_window(window, title, self.title)

        # start the progress indicator
        self.progress = ProgressMeter(self.title, _('Starting'),
                                      parent=uistate.window)
        self.progress.set_pass(_('Looking for possible loop for each person'),
                               self.db.get_number_of_people())

        self.model = Gtk.ListStore(
            GObject.TYPE_STRING,    # 0==father id
            GObject.TYPE_STRING,    # 1==father
            GObject.TYPE_STRING,    # 2==son id
            GObject.TYPE_STRING,    # 3==son
            GObject.TYPE_STRING,    # 4==family gid
            GObject.TYPE_STRING)    # 5==loop number
        self.model.set_sort_column_id(
            Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0)

        self.treeview = top_dialog.get_object("treeview")
        self.treeview.set_model(self.model)
        col0 = Gtk.TreeViewColumn('',
                                  Gtk.CellRendererText(), text=5)
        col1 = Gtk.TreeViewColumn(_('Gramps ID'),
                                  Gtk.CellRendererText(), text=0)
        col2 = Gtk.TreeViewColumn(_('Parent'),
                                  Gtk.CellRendererText(), text=1)
        col3 = Gtk.TreeViewColumn(_('Gramps ID'),
                                  Gtk.CellRendererText(), text=2)
        col4 = Gtk.TreeViewColumn(_('Child'),
                                  Gtk.CellRendererText(), text=3)
        col5 = Gtk.TreeViewColumn(_('Family ID'),
                                  Gtk.CellRendererText(), text=4)
        col1.set_resizable(True)
        col2.set_resizable(True)
        col3.set_resizable(True)
        col4.set_resizable(True)
        col5.set_resizable(True)
        col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.treeview.append_column(col0)
        self.treeview.append_column(col1)
        self.treeview.append_column(col2)
        self.treeview.append_column(col3)
        self.treeview.append_column(col4)
        self.treeview.append_column(col5)
        self.treeselection = self.treeview.get_selection()
        self.treeview.connect('row-activated', self.rowactivated_cb)

        self.curr_fam = None
        people = self.db.get_person_handles()
        self.total = len(people)  # total number of people to process.
        self.count = 0  # current number of people completely processed
        self.loop = 0  # Number of loops found for GUI

        pset = OrderedDict()
        # pset is the handle list of persons from the current start of
        # exploration path to the current limit.  The use of OrderedDict
        # allows us to use it as a LIFO during recursion, as well as makes for
        # quick lookup.  If we find a loop, pset provides a nice way to get
        # the loop path.
        self.done = set()
        # self.done is the handle set of people that have been fully explored
        # and do NOT have loops in the decendent tree.  We use this to avoid
        # repeating work when we encounter one of these during the search.
        for person_handle in people:
            person = self.db.get_person_from_handle(person_handle)
            self.current = person
            self.parent = None
            self.descendants(person_handle, pset)

        # close the progress bar
        self.progress.close()

        self.show()

    def descendants(self, person_handle, pset):
        """
        Find the descendants of a given person.
        Returns False if a loop for the person is NOT found, True if loop found
        We use the return value to ensure a person is not put on done list if
        part of a loop
        """
        if person_handle in self.done:
            return False  # We have already verified no loops for this one
        if person_handle in pset:
            # We found one loop.
            # person_handle is child, self.parent, self.curr_fam valid
            # see if it has already been put into display
            person = self.db.get_person_from_handle(person_handle)
            pers_id = person.get_gramps_id()
            pers_name = _nd.display(person)
            parent_id = self.parent.get_gramps_id()
            parent_name = _nd.display(self.parent)
            value = (parent_id, parent_name, pers_id, pers_name, self.curr_fam)
            found = False
            for pth in range(len(self.model)):
                path = Gtk.TreePath(pth)
                treeiter = self.model.get_iter(path)
                find = (self.model.get_value(treeiter, 0),
                        self.model.get_value(treeiter, 1),
                        self.model.get_value(treeiter, 2),
                        self.model.get_value(treeiter, 3),
                        self.model.get_value(treeiter, 4))
                if find == value:
                    found = True  # This loop is in display model
                    break
            if not found:
                # Need to put loop in display model.
                self.loop += 1
                # place first node
                self.model.append(value + (str(self.loop),))
                state = 0
                # Now search for loop beginning.
                for hndl in pset.keys():
                    if hndl != person_handle and state == 0:
                        continue  # beginning not found
                    if state == 0:
                        state = 1  # found beginning, get first item to display
                        continue
                    # we have a good handle, now put item on display list
                    self.parent = person
                    person = self.db.get_person_from_handle(hndl)
                    # Get the family that is both parent/person
                    for fam_h in person.get_parent_family_handle_list():
                        if fam_h in self.parent.get_family_handle_list():
                            break
                    family = self.db.get_family_from_handle(fam_h)
                    fam_id = family.get_gramps_id()
                    pers_id = person.get_gramps_id()
                    pers_name = _nd.display(person)
                    parent_id = self.parent.get_gramps_id()
                    parent_name = _nd.display(self.parent)
                    value = (parent_id, parent_name, pers_id, pers_name,
                             fam_id, str(self.loop))
                    self.model.append(value)
            return True
        # We are not part of loop (yet) so search descendents
        person = self.db.get_person_from_handle(person_handle)
        # put in the pset path list for recursive calls to find
        pset[person_handle] = None
        loop = False
        for family_handle in person.get_family_handle_list():
            family = self.db.get_family_from_handle(family_handle)
            if not family:
                # can happen with LivingProxyDb(PrivateProxyDb(db))
                continue
            for child_ref in family.get_child_ref_list():
                child_handle = child_ref.ref
                self.curr_fam = family.get_gramps_id()
                self.parent = person
                # if any descendants are part of loop, so is search person
                loop |= self.descendants(child_handle, pset)
        # we have completed search, we can pop the person off pset list
        person_handle, dummy = pset.popitem(last=True)

        if not loop:
            # person was not in loop, so add to done list and update progress
            self.done.add(person_handle)
            self.count += 1
            self.progress.set_header("%d/%d" % (self.count, self.total))
            self.progress.step()
            return False
        # person was in loop...
        return True

    def rowactivated_cb(self, treeview, path, column):
        """
        Called when a row is activated.
        """
        # first we need to check that the row corresponds to a person
        iter_ = self.model.get_iter(path)
        fam_id = self.model.get_value(iter_, 4)
        fam = self.dbstate.db.get_family_from_gramps_id(fam_id)
        if fam:
            try:
                EditFamily(self.dbstate, self.uistate, [], fam)
            except WindowActiveError:
                pass
            return True
        return False

    def on_help_clicked(self, obj):
        """
        Display the relevant portion of Gramps manual.
        """
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def close(self, *obj):
        ManagedWindow.close(self, *obj)
Exemple #31
0
class EventComparisonResults(ManagedWindow):
    def __init__(self, dbstate, uistate, people_list, track):
        self.dbstate = dbstate
        self.uistate = uistate

        ManagedWindow.__init__(self, uistate, track, self)

        self.db = dbstate.db
        self.my_list = people_list
        self.row_data = []
        self.save_form = None

        self.topDialog = Glade(toplevel="eventcmp")
        self.topDialog.connect_signals({
            "on_write_table": self.on_write_table,
            "destroy_passed_object": self.close,
            "on_help_clicked": self.on_help_clicked,
            "on_apply_clicked": self.__dummy,
            "on_editor_clicked": self.__dummy,
        })

        window = self.topDialog.toplevel
        self.set_window(window, self.topDialog.get_object('title'),
                        _('Event Comparison Results'))
        self.setup_configs('interface.eventcomparisonresults', 750, 400)

        self.eventlist = self.topDialog.get_object('treeview')
        self.sort = Sort(self.db)
        self.my_list.sort(key=self.sort.by_last_name_key)

        self.event_titles = self.make_event_titles()

        self.table_titles = [_("Person"), _("ID")]
        for event_name in self.event_titles:
            self.table_titles.append(
                _("%(event_name)s Date") % {'event_name': event_name})
            self.table_titles.append('sort')  # This won't be shown in a tree
            self.table_titles.append(
                _("%(event_name)s Place") % {'event_name': event_name})

        self.build_row_data()
        self.draw_display()
        self.show()

    def __dummy(self, obj):
        """dummy callback, needed because widget is in same glade file
        as another widget, so callbacks must be defined to avoid warnings.
        """
        pass

    def on_help_clicked(self, obj):
        """Display the relevant portion of Gramps manual"""
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def build_menu_names(self, obj):
        return (_("Event Comparison Results"), None)

    def draw_display(self):

        model_index = 0
        tree_index = 0
        mylist = []
        renderer = Gtk.CellRendererText()
        for title in self.table_titles:
            mylist.append(str)
            if title == 'sort':
                # This will override the previously defined column
                self.eventlist.get_column(tree_index -
                                          1).set_sort_column_id(model_index)
            else:
                column = Gtk.TreeViewColumn(title, renderer, text=model_index)
                column.set_sort_column_id(model_index)
                self.eventlist.append_column(column)
                # This one numbers the tree columns: increment on new column
                tree_index += 1
            # This one numbers the model columns: always increment
            model_index += 1

        model = Gtk.ListStore(*mylist)
        self.eventlist.set_model(model)

        self.progress_bar.set_pass(_('Building display'), len(self.row_data))
        for data in self.row_data:
            model.append(row=list(data))
            self.progress_bar.step()
        self.progress_bar.close()

    def build_row_data(self):
        self.progress_bar = ProgressMeter(_('Comparing Events'),
                                          '',
                                          parent=self.uistate.window)
        self.progress_bar.set_pass(_('Building data'), len(self.my_list))
        for individual_id in self.my_list:
            individual = self.db.get_person_from_handle(individual_id)
            name = individual.get_primary_name().get_name()
            gid = individual.get_gramps_id()

            the_map = defaultdict(list)
            for ievent_ref in individual.get_event_ref_list():
                ievent = self.db.get_event_from_handle(ievent_ref.ref)
                event_name = str(ievent.get_type())
                the_map[event_name].append(ievent_ref.ref)

            first = True
            done = False
            while not done:
                added = False
                tlist = [name, gid] if first else ["", ""]

                for ename in self.event_titles:
                    if ename in the_map and len(the_map[ename]) > 0:
                        event_handle = the_map[ename][0]
                        del the_map[ename][0]
                        date = place = ""

                        if event_handle:
                            event = self.db.get_event_from_handle(event_handle)
                            date = get_date(event)
                            sortdate = "%09d" % (
                                event.get_date_object().get_sort_value())
                            place_handle = event.get_place_handle()
                            if place_handle:
                                place = self.db.get_place_from_handle(
                                    place_handle).get_title()
                        tlist += [date, sortdate, place]
                        added = True
                    else:
                        tlist += [""] * 3

                if first:
                    first = False
                    self.row_data.append(tlist)
                elif not added:
                    done = True
                else:
                    self.row_data.append(tlist)
            self.progress_bar.step()

    def make_event_titles(self):
        """
        Create the list of unique event types, along with the person's
        name, birth, and death.
        This should be the column titles of the report.
        """
        the_map = defaultdict(int)
        for individual_id in self.my_list:
            individual = self.db.get_person_from_handle(individual_id)
            for event_ref in individual.get_event_ref_list():
                event = self.db.get_event_from_handle(event_ref.ref)
                name = str(event.get_type())
                if not name:
                    break
                the_map[name] += 1

        unsort_list = sorted([(d, k) for k, d in the_map.items()],
                             key=lambda x: x[0],
                             reverse=True)

        sort_list = [item[1] for item in unsort_list]
        ## Presently there's no Birth and Death. Instead there's Birth Date and
        ## Birth Place, as well as Death Date and Death Place.
        ##         # Move birth and death to the begining of the list
        ##         if _("Death") in the_map:
        ##             sort_list.remove(_("Death"))
        ##             sort_list = [_("Death")] + sort_list

        ##         if _("Birth") in the_map:
        ##             sort_list.remove(_("Birth"))
        ##             sort_list = [_("Birth")] + sort_list

        return sort_list

    def on_write_table(self, obj):
        f = Gtk.FileChooserDialog(_("Select filename"),
                                  parent=self.window,
                                  action=Gtk.FileChooserAction.SAVE,
                                  buttons=(_('_Cancel'),
                                           Gtk.ResponseType.CANCEL, _('_Save'),
                                           Gtk.ResponseType.OK))

        f.set_current_folder(get_curr_dir())
        status = f.run()
        f.hide()

        if status == Gtk.ResponseType.OK:
            name = f.get_filename()
            doc = ODSTab(len(self.row_data))
            doc.creator(self.db.get_researcher().get_name())

            spreadsheet = TableReport(name, doc)

            new_titles = []
            skip_columns = []
            index = 0
            for title in self.table_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.row_data:
                spreadsheet.set_row(index % 2)
                index += 1
                spreadsheet.write_table_data(top, skip_columns)

            spreadsheet.finalize()
        f.destroy()
Exemple #32
0
class MergeCitations(tool.BatchTool, ManagedWindow):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.set_window(Gtk.Window(), Gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)

        if not self.fail:
            uistate.set_busy_cursor(True)
            self.run()
            uistate.set_busy_cursor(False)

    def run(self):

        top = Glade(toplevel="mergecitations")

        # retrieve options
        fields = self.options.handler.options_dict['fields']
        dont_merge_notes = self.options.handler.options_dict[
            'dont_merge_notes']

        my_menu = Gtk.ListStore(str, object)
        for val in sorted(_val2label):
            my_menu.append([_val2label[val], val])

        self.notes_obj = top.get_object("notes")
        self.notes_obj.set_active(dont_merge_notes)
        self.notes_obj.show()

        self.menu = top.get_object("menu")
        self.menu.set_model(my_menu)
        self.menu.set_active(fields)

        window = top.toplevel
        window.show()
        #        self.set_window(window, top.get_object('title'),
        #                        _('Merge citations'))
        self.set_window(
            window, top.get_object('title2'),
            _("Notes, media objects and data-items of matching "
              "citations will be combined."))

        top.connect_signals({
            "on_merge_ok_clicked": self.on_merge_ok_clicked,
            "destroy_passed_object": self.cancel,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_merge_event": self.close,
            "on_delete_event": self.close,
        })

        self.show()

    def cancel(self, obj):
        """
        on cancel, update the saved values of the options.
        """
        fields = self.menu.get_model()[self.menu.get_active()][1]
        dont_merge_notes = int(self.notes_obj.get_active())
        LOG.debug("cancel fields %d dont_merge_notes %d" %
                  (fields, dont_merge_notes))

        self.options.handler.options_dict['fields'] = fields
        self.options.handler.options_dict[
            'dont_merge_notes'] = dont_merge_notes
        # Save options
        self.options.handler.save_options()

        self.close(obj)

    def build_menu_names(self, obj):
        return (_("Tool settings"), _("Merge citations tool"))

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""

        display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC)

    def on_merge_ok_clicked(self, obj):
        """
        Performs the actual merge of citations
        (Derived from ExtractCity)
        """
        fields = self.menu.get_model()[self.menu.get_active()][1]
        dont_merge_notes = int(self.notes_obj.get_active())
        LOG.debug("fields %d dont_merge_notes %d" % (fields, dont_merge_notes))

        self.options.handler.options_dict['fields'] = fields
        self.options.handler.options_dict[
            'dont_merge_notes'] = dont_merge_notes
        # Save options
        self.options.handler.save_options()

        self.progress = ProgressMeter(_('Checking Sources'), '')
        self.progress.set_pass(_('Looking for citation fields'),
                               self.db.get_number_of_citations())

        db = self.dbstate.db

        db.disable_signals()
        num_merges = 0
        for handle in db.iter_source_handles():
            dict = {}
            citation_handle_list = list(db.find_backlink_handles(handle))
            for (class_name, citation_handle) in citation_handle_list:
                if class_name != Citation.__name__:
                    raise MergeError("Encountered an object of type %s "
                                     "that has a citation reference." %
                                     class_name)

                citation = db.get_citation_from_handle(citation_handle)
                if citation is None:
                    continue
                key = citation.get_page()
                if fields != IGNORE_DATE and fields != IGNORE_BOTH:
                    key += "\n" + get_date(citation)
                if fields != IGNORE_CONFIDENCE and fields != IGNORE_BOTH:
                    key += "\n" + \
                        conf_strings[citation.get_confidence_level()]
                if key in dict and \
                    (not dont_merge_notes or len(citation.note_list) == 0):
                    citation_match_handle = dict[key]
                    citation_match = \
                        db.get_citation_from_handle(citation_match_handle)
                    try:
                        query = MergeCitationQuery(self.dbstate,
                                                   citation_match, citation)
                        query.execute()
                    except AssertionError:
                        print("Tool/Family Tree processing/MergeCitations", \
                        "citation1 gramps_id", citation_match.get_gramps_id(), \
                        "citation2 gramps_id", citation.get_gramps_id() , \
                        "citation backlink handles", \
                        list(db.find_backlink_handles(citation.get_handle())))
                    num_merges += 1
                elif (not dont_merge_notes or len(citation.note_list) == 0):
                    dict[key] = citation_handle
                self.progress.step()
        db.enable_signals()
        db.request_rebuild()
        self.progress.close()
        OkDialog(
            _("Number of merges done"),
            # translators: leave all/any {...} untranslated
            ngettext("{number_of} citation merged",
                     "{number_of} citations merged",
                     num_merges).format(number_of=num_merges))
        self.close(obj)
Exemple #33
0
class ChangeNames(tool.BatchTool, ManagedWindow):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _('Capitalization changes')
        self.cb = callback

        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        self.progress = ProgressMeter(  # parent-OK
            _('Checking Family Names'),
            '',
            parent=uistate.window)
        self.progress.set_pass(_('Searching family names'),
                               len(self.db.get_surname_list()))
        self.name_list = []

        for name in self.db.get_surname_list():
            name.strip()
            namesplitSP = name.split()
            lSP = len(namesplitSP)
            namesplitHY = name.split('-')
            lHY = len(namesplitHY)
            if lSP == lHY == 1:
                if name != name.capitalize():
                    # Single surname without hyphen(s)
                    self.name_list.append(name)
            #if lSP == 1 and lHY > 1:
            #print "LSP==1", name, name.capitalize()
            #if name != name.capitalize():
            # Single surname with hyphen(s)
            #self.name_list.append(name)
            if lSP > 1 and lHY == 1:
                # more than one string in surname but no hyphen
                # check if first string is in prefix_list, if so test for cap in rest
                s1 = 0
                if namesplitSP[0].lower() in prefix_list:
                    s1 = 1
                for x in range(len(namesplitSP) - s1):
                    # check if any subsurname is not cap
                    notcap = False
                    if namesplitSP[s1 + x] != namesplitSP[s1 + x].capitalize():
                        notcap = True
                        break
                if notcap:
                    # Multiple surnames possibly after prefix
                    self.name_list.append(name)
            if lHY > 1:
                # more than one string in surname but hyphen(s) exists
                # check if first string is in prefix_list, if so test for cap
                if namesplitSP[0].lower() in prefix_list:
                    namesplitHY[0] = namesplitHY[0].replace(
                        namesplitSP[0], '').strip()
                for x in range(len(namesplitHY)):
                    # check if any subsurname is not cap
                    notcap = False
                    if namesplitHY[x] != namesplitHY[x].capitalize():
                        notcap = True
                        break
                if notcap:
                    # Multiple surnames possibly after frefix
                    self.name_list.append(name)

            if uistate:
                self.progress.step()

        if self.name_list:
            self.display()
        else:
            self.progress.close()
            self.close()
            OkDialog(
                _('No modifications made'),  # parent-OK
                _("No capitalization changes were detected."),
                parent=uistate.window)

    def name_cap(self, name):
        name.strip()
        namesplitSP = name.split()
        lSP = len(namesplitSP)
        lHY = len(name.split('-'))
        namesep = ' '
        if lHY > 1:
            namesep = '-'
            namesplitSP = name.replace(namesep, ' ').split()
            lSP = len(namesplitSP)
        if lSP == lHY == 1:
            #if name != name.capitalize():
            # Single surname without space(s) or hyphen(s), normal case
            return name.capitalize()
        else:
            # more than one string in surname but no hyphen
            # check if first string is in prefix_list, if so CAP the rest
            # Names like (von) Kohl(-)Brandt
            result = ""
            s1 = 0
            if namesplitSP[0].lower() in prefix_list:
                s1 = 1
                result = namesplitSP[0].lower() + ' '
            for x in range(lSP - s1):
                # CAP all subsurnames
                result = result + namesplitSP[s1 + x].capitalize() + namesep
            return result[:-1]

    def display(self):

        self.top = Glade()
        window = self.top.toplevel
        self.top.connect_signals({
            "destroy_passed_object": self.close,
            "on_ok_clicked": self.on_ok_clicked,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_event": self.close,
        })

        self.list = self.top.get_object("list")
        self.set_window(window, self.top.get_object('title'), self.label)

        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING)

        r = Gtk.CellRendererToggle()
        r.connect('toggled', self.toggled)
        c = Gtk.TreeViewColumn(_('Select'), r, active=0)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Original Name'),
                               Gtk.CellRendererText(),
                               text=1)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Capitalization Change'),
                               Gtk.CellRendererText(),
                               text=2)
        self.list.append_column(c)

        self.list.set_model(self.model)

        self.iter_list = []
        self.progress.set_pass(_('Building display'), len(self.name_list))
        for name in self.name_list:
            handle = self.model.append()
            self.model.set_value(handle, 0, True)
            self.model.set_value(handle, 1, name)
            namecap = self.name_cap(name)
            self.model.set_value(handle, 2, namecap)
            self.iter_list.append(handle)
            self.progress.step()
        self.progress.close()

        self.show()

    def toggled(self, cell, path_string):
        path = tuple(map(int, path_string.split(':')))
        row = self.model[path]
        row[0] = not row[0]

    def build_menu_names(self, obj):
        return (self.label, None)

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC)

    def on_ok_clicked(self, obj):
        with DbTxn(_("Capitalization changes"), self.db,
                   batch=True) as self.trans:
            self.db.disable_signals()
            changelist = set(
                self.model.get_value(node, 1) for node in self.iter_list
                if self.model.get_value(node, 0))

            #with self.db.get_person_cursor(update=True, commit=True) as cursor:
            #  for handle, data in cursor:
            for handle in self.db.get_person_handles(False):
                person = self.db.get_person_from_handle(handle)
                #person = Person(data)
                change = False
                for name in [person.get_primary_name()
                             ] + person.get_alternate_names():
                    sname = find_surname_name(handle, name.serialize())
                    if sname in changelist:
                        change = True
                        for surn in name.get_surname_list():
                            sname = self.name_cap(surn.get_surname())
                            surn.set_surname(sname)
                if change:
                    #cursor.update(handle, person.serialize())
                    self.db.commit_person(person, self.trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        # FIXME: this probably needs to be removed, and bookmarks
        # should always be rebuilt on a commit_person via signals
        # self.parent.bookmarks.redraw()
        self.close()
        self.cb()
Exemple #34
0
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
    """ Class for Reodering Gramps ID Tool """
    xobjects = (('person', 'people'), ('family', 'families'),
                ('event', 'events'), ('place', 'places'),
                ('source', 'sources'), ('citation', 'citations'),
                ('repository', 'repositories'),
                ('media', 'media'), ('note', 'notes'))

    def build_menu_names_(self, widget=None):
        """ The menu name """
        return (_('Main window'), _("Reorder Gramps IDs"))

    def __init__(self, dbstate, user, options_class, name, callback=None):
        self.uistate = user.uistate
        self.db = dbstate.db

        if self.uistate:
            tool.BatchTool.__init__(self, dbstate, user, options_class, name)
            if self.fail:
                return   # user denied to modify Gramps IDs

        ManagedWindow.__init__(self, self.uistate, [], self.__class__)
        if not self.uistate:
            UpdateCallback.__init__(self, user.callback)

        self.object_status = True
        self.change_status = False
        self.start_zero = True
        self.step_cnt, self.step_list = 0, ['1', '2', '5', '10']
        self.keep_status = True

        self.obj_values = {}   # enable access to all internal values
        self.active_entries, self.format_entries = {}, {}
        self.change_entries = {}
        self.start_entries, self.step_entries = {}, {}
        self.keep_entries = {}

        self.prim_methods, self.obj_methods = {}, {}
        for prim_obj, prim_objs in self.xobjects:
            iter_handles = "iter_%s_handles" % prim_obj
            get_number_obj = "get_number_of_%s" % prim_objs
            prefix_fmt = "%s_prefix" % prim_obj
            get_from_id = "get_%s_from_gramps_id" % prim_obj
            get_from_handle = "get_%s_from_handle" % prim_obj
            next_from_id = "find_next_%s_gramps_id" % prim_obj
            commit = "commit_%s" % prim_obj

            self.prim_methods[prim_obj] = (getattr(self.db, prefix_fmt),
                                           getattr(self.db, get_number_obj)(),
                                           getattr(self.db, next_from_id)())
            self.obj_methods[prim_obj] = (getattr(self.db, iter_handles),
                                          getattr(self.db, commit),
                                          getattr(self.db, get_from_id),
                                          getattr(self.db, get_from_handle),
                                          getattr(self.db, next_from_id))

            object_fmt, quant_id, next_id = self.prim_methods[prim_obj]

            obj_value = ReorderEntry(object_fmt, quant_id, next_id, prim_obj)
            self.obj_values[prim_obj] = obj_value

        if self.uistate:
            self._display()
        else:
            self._execute()

    def __on_object_button_clicked(self, widget=None):
        """ compute all primary objects and toggle the 'Active' attribute """
        self.object_status = not self.object_status

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_active' % prim_obj)
            obj.set_active(self.object_status)

    def __on_object_button_toggled(self, widget):
        """ compute the primary object and toggle the 'Sensitive' attribute """
        obj_state = widget.get_active()
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]

        self.active_entries[obj_name].set_val(obj_state)

        for obj_entry in ['actual', 'quant', 'format', 'change']:
            obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
            obj.set_sensitive(obj_state)

        for obj_entry in ['start', 'step', 'keep']:
            obj = self.top.get_object('%s_change' % obj_name)
            if obj.get_active():
                obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
                obj.set_sensitive(obj_state)

    def __on_format_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Format' scheme of identifiers """
        for prim_obj, dummy in self.xobjects:
            obj_format = self.top.get_object('%s_format' % prim_obj)
            if not obj_format.get_sensitive():
                continue

            obj_fmt = self.obj_values[prim_obj].res_fmt()
            self.format_entries[prim_obj].force_value(obj_fmt)
            if self.start_zero:
                obj_id = self.obj_values[prim_obj].zero_id()
            else:
                obj_id = self.obj_values[prim_obj].last_id()
            self.start_entries[prim_obj].force_value(obj_id)

    def __on_change_button_clicked(self, widget=None):
        """ compute all primary objects and toggle the 'Change' attribute """
        self.change_status = not self.change_status

        for prim_obj, dummy in self.xobjects:
            obj_change = self.top.get_object('%s_change' % prim_obj)
            if not obj_change.get_sensitive():
                continue

            self.change_entries[prim_obj].set_val(self.change_status)
            obj_change.set_active(self.change_status)

    def __on_change_button_toggled(self, widget):
        """ compute the primary object and toggle the 'Sensitive' attribute """
        obj_state = widget.get_active()
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]

        for obj_entry in ['start', 'step', 'keep']:
            obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
            if obj_entry == 'keep':
                if (self.obj_values[obj_name].stored_prefix !=
                        self.obj_values[obj_name].object_prefix and
                        self.obj_values[obj_name].stored_suffix !=
                        self.obj_values[obj_name].object_suffix):
                    self.keep_entries[obj_name].set_val(False)
                else:
                    obj.set_active(obj_state)
                    self.keep_entries[obj_name].set_val(obj_state)
            obj.set_sensitive(obj_state)

    def __on_start_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Start' values of identifiers """
        self.start_zero = not self.start_zero

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_start' % prim_obj)
            if not obj.get_sensitive():
                continue

            if self.start_zero:
                obj_id = self.obj_values[prim_obj].zero_id()
            else:
                obj_id = self.obj_values[prim_obj].next_id()
            self.start_entries[prim_obj].force_value(obj_id)

    def __on_step_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Step' width of identifiers """
        self.step_cnt = self.step_cnt + 1 if self.step_cnt < 3 else 0

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_step' % prim_obj)
            if not obj.get_sensitive():
                continue

            step_val = self.step_list[self.step_cnt]
            self.step_entries[prim_obj].force_value(step_val)

    def __on_keep_button_clicked(self, widget=None):
        """ compute the primary object and toggle the 'Active' attribute """
        self.keep_status = not self.keep_status

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_change' % prim_obj)
            if not obj.get_active():
                continue

            obj = self.top.get_object('%s_keep' % prim_obj)
            obj.set_active(self.keep_status)
            self.keep_entries[prim_obj].set_val(self.keep_status)

    def __on_format_entry_keyrelease(self, widget, event, data=None):
        """ activated on all return's of an entry """
        if event.keyval in [Gdk.KEY_Return]:
            obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
            obj_fmt = self.format_entries[obj_name].get_val()
            self.format_entries[obj_name].force_value(obj_fmt)
            self.start_entries[obj_name].update()

            obj_change = self.top.get_object('%s_change' % obj_name)
            obj_change.grab_focus()

        return False

    def __on_format_entry_focusout(self, widget, event, data=None):
        """ activated on all focus out of an entry """
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
        obj_fmt = self.format_entries[obj_name].get_val()

        self.format_entries[obj_name].set_text(obj_fmt)
        self.start_entries[obj_name].update()

        return False

    def __on_start_entry_focusout(self, widget, event, data=None):
        """ activated on all focus out of an entry """
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
        self.start_entries[obj_name].update()

        return False

    def __on_ok_button_clicked(self, widget=None):
        """ execute the reodering and close """
        self._execute()
        self._update()

        self.close()

    def __on_cancel_button_clicked(self, widget=None):
        """ cancel the reodering and close """
        self.close()

    def __on_help_button_clicked(self, widget=None):
        """ display the relevant portion of Gramps manual """
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def _display(self):
        """ organize Glade 'Reorder IDs' window """

        # get the main window from glade
        self.top = Glade(toplevel="reorder-ids")
        window = self.top.toplevel

        # set gramps style title for the window
        self.set_window(window, self.top.get_object("title"),
                        _("Reorder Gramps IDs"))

        # connect signals
        self.top.connect_signals({
            "on_object_button_clicked" : self.__on_object_button_clicked,
            "on_object_button_toggled" : self.__on_object_button_toggled,
            "on_format_button_clicked" : self.__on_format_button_clicked,
            "on_start_button_clicked" : self.__on_start_button_clicked,
            "on_step_button_clicked" : self.__on_step_button_clicked,
            "on_keep_button_clicked" : self.__on_keep_button_clicked,
            "on_change_button_clicked" : self.__on_change_button_clicked,
            "on_change_button_toggled" : self.__on_change_button_toggled,
            "on_format_entry_keyrelease" : self.__on_format_entry_keyrelease,
            "on_format_entry_focusout" : self.__on_format_entry_focusout,
            "on_start_entry_focusout" : self.__on_start_entry_focusout,
            "on_help_button_clicked" : self.__on_help_button_clicked,
            "on_cancel_button_clicked" : self.__on_cancel_button_clicked,
            "on_ok_button_clicked" : self.__on_ok_button_clicked
        })

        # Calculate all entries and update Glade window
        for prim_obj, dummy in self.xobjects:
            # populate Object, Actual & Quantity fields with values
            obj_active = self.top.get_object('%s_active' % prim_obj)
            self.active_entries[prim_obj] = MonitoredCheckbox(
                obj_active, obj_active, self.obj_values[prim_obj].set_active,
                self.obj_values[prim_obj].get_active)
            obj_actual = self.top.get_object('%s_actual' % prim_obj)
            obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id())
            obj_quant = self.top.get_object('%s_quant' % prim_obj)
            obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id))

            # connect/populate Format, Start, Step, Keep & Change fields
            #  with GTK/values
            obj_format = self.top.get_object('%s_format' % prim_obj)
            self.format_entries[prim_obj] = MonitoredEntry(
                obj_format, self.obj_values[prim_obj].set_fmt,
                self.obj_values[prim_obj].get_fmt)
            obj_change = self.top.get_object('%s_change' % prim_obj)
            self.change_entries[prim_obj] = MonitoredCheckbox(
                obj_change, obj_change, self.obj_values[prim_obj].set_change,
                self.obj_values[prim_obj].get_change)
            obj_start = self.top.get_object('%s_start' % prim_obj)
            self.start_entries[prim_obj] = MonitoredEntry(
                obj_start, self.obj_values[prim_obj].set_id,
                self.obj_values[prim_obj].get_id)
            obj_step = self.top.get_object('%s_step' % prim_obj)
            self.step_entries[prim_obj] = MonitoredEntry(
                obj_step, self.obj_values[prim_obj].set_step,
                self.obj_values[prim_obj].get_step,
                changed=self.obj_values[prim_obj].change_step)
            obj_keep = self.top.get_object('%s_keep' % prim_obj)
            self.keep_entries[prim_obj] = MonitoredCheckbox(
                obj_keep, obj_keep, self.obj_values[prim_obj].set_keep,
                self.obj_values[prim_obj].get_keep, readonly=True)

        # fetch the popup menu
        self.menu = self.top.get_object("popup_menu")

        # ok, let's see what we've done
        self.window.resize(700, 410)
        self.show()

    def _update(self):
        """ store changed objects formats in DB """

        update = False
        for prim_obj, dummy in self.xobjects:
            obj_value = self.obj_values[prim_obj]
            if obj_value.object_fmt != obj_value.stored_fmt:
                constant = 'preferences.%sprefix' % PREFIXES[prim_obj]
                config.set(constant, obj_value.object_fmt)
                update = True

        if update:
            config.save()
            self.db.set_prefixes(
                config.get('preferences.iprefix'),
                config.get('preferences.oprefix'),
                config.get('preferences.fprefix'),
                config.get('preferences.sprefix'),
                config.get('preferences.cprefix'),
                config.get('preferences.pprefix'),
                config.get('preferences.eprefix'),
                config.get('preferences.rprefix'),
                config.get('preferences.nprefix'))

    def _execute(self):
        """ execute all primary objects and reorder if neccessary """

        # Update progress calculation
        if self.uistate:
            self.progress = ProgressMeter(_('Reorder Gramps IDs'), '')
        else:
            total_objs = 0
            for prim_obj, dummy in self.xobjects:
                if self.obj_values[prim_obj].active_obj:
                    total_objs += self.obj_values[prim_obj].quant_id
            self.set_total(total_objs)

        # Update database
        self.db.disable_signals()
        for prim_obj, prim_objs in self.xobjects:
            with DbTxn(_('Reorder %s IDs ...') % prim_obj,
                       self.db, batch=True) as self.trans:
                if self.obj_values[prim_obj].active_obj:
                    if self.uistate:
                        self.progress.set_pass(
                            _('Reorder %s IDs ...') % _(prim_objs.title()),
                            self.obj_values[prim_obj].quant_id)
                    # Process reordering
                    self._reorder(prim_obj)

        self.db.enable_signals()
        self.db.request_rebuild()

        # Update progress calculation
        if self.uistate:
            self.progress.close()
        else:
            print('\nDone.')

    # finds integer portion in a GrampsID
    _findint = re.compile('^[^\d]*(\d+)[^\d]*$')
    # finds prefix, number, suffix of a Gramps ID ignoring a leading or
    # trailing space.  The number must be at least three digits.
    _prob_id = re.compile('^ *([^\d]*)(\d{3,9})([^\d]*) *$')

    def _reorder(self, prim_obj):
        """ reorders all selected objects with a (new) style, start & step """

        dup_ids = []   # list of duplicate identifiers
        new_ids = {}   # list of new identifiers

        iter_handles, commit, get_from_id, get_from_handle, next_from_id = \
            self.obj_methods[prim_obj]

        prefix_fmt = self.obj_values[prim_obj].get_fmt()
        prefix = self.obj_values[prim_obj].object_prefix
        suffix = self.obj_values[prim_obj].object_suffix
        old_pref = self.obj_values[prim_obj].stored_prefix
        old_suff = self.obj_values[prim_obj].stored_suffix
        new_id = self.obj_values[prim_obj].get_id()
        keep_fmt = self.obj_values[prim_obj].get_keep()
        change = self.obj_values[prim_obj].get_change()
        index_max = int("9" * self.obj_values[prim_obj].width_fmt)
        do_same = False

        for handle in iter_handles():
            # Update progress
            if self.uistate:
                self.progress.step()
            else:
                self.update()

            # extract basic data out of the database
            obj = get_from_handle(handle)

            act_id = obj.get_gramps_id()
            # here we see if the ID looks like a new or previous or default
            # Gramps ID.
            # If not we ask user if he really wants to replace it.
            # This should allow user to protect a GetGov ID or similar
            match = self._prob_id.match(act_id)
            if not (match and
                    (prefix == match.groups()[0] and
                     suffix == match.groups()[2] or
                     old_pref == match.groups()[0] and
                     old_suff == match.groups()[2] or
                     len(match.groups()[0]) == 1 and
                     len(match.groups()[2]) == 0)) and not do_same:
                xml = Glade(toplevel='dialog')

                top = xml.toplevel
                # self.top.set_icon(ICON)
                top.set_title("%s - Gramps" % _("Reorder Gramps IDs"))
                apply_to_rest = xml.get_object('apply_to_rest')

                label1 = xml.get_object('toplabel')
                label1.set_text('<span weight="bold" size="larger">%s</span>' %
                                _("Reorder Gramps IDs"))
                label1.set_use_markup(True)

                label2 = xml.get_object('mainlabel')
                label2.set_text(_("Do you want to replace %s?" % act_id))
                top.set_transient_for(self.progress._ProgressMeter__dialog)
                self.progress._ProgressMeter__dialog.set_modal(False)
                top.show()
                response = top.run()
                do_same = apply_to_rest.get_active()
                top.destroy()
                self.progress._ProgressMeter__dialog.set_modal(True)
                if response != Gtk.ResponseType.YES:
                    continue

            elif not match and do_same and response != Gtk.ResponseType.YES:
                continue

            if change:
                # update the defined ID numbers into objects under
                # consideration of keeping ID if format not matches prefix
                # (implication logical boolean operator below)
                if act_id.startswith(prefix) and act_id.endswith(suffix) or \
                        not keep_fmt:
                    obj.set_gramps_id(new_id)
                    commit(obj, self.trans)
                    new_id = self.obj_values[prim_obj].succ_id()
            else:
                # attempt to extract integer - if we can't, treat it as a
                # duplicate
                try:
                    match = self._findint.match(act_id)
                    if match:
                        # get the integer, build the new handle. Make sure it
                        # hasn't already been chosen. If it has, put this
                        # in the duplicate handle list

                        index = int(match.groups()[0])
                        if index > index_max:
                            new_id = next_from_id()
                        else:
                            new_id = prefix_fmt % index

                        if new_id == act_id:
                            if new_id in new_ids:
                                dup_ids.append(obj.get_handle())
                            else:
                                new_ids[new_id] = act_id
                        elif get_from_id(new_id) is not None:
                            dup_ids.append(obj.get_handle())
                        else:
                            obj.set_gramps_id(new_id)
                            commit(obj, self.trans)
                            new_ids[new_id] = act_id
                    else:
                        dup_ids.append(handle)
                except:
                    dup_ids.append(handle)

        # go through the duplicates, looking for the first available
        # handle that matches the new scheme.
        if dup_ids:
            if self.uistate:
                self.progress.set_pass(_('Finding and assigning unused IDs.'),
                                       len(dup_ids))
            for handle in dup_ids:
                obj = get_from_handle(handle)
                obj.set_gramps_id(next_from_id())
                commit(obj, self.trans)
Exemple #35
0
class PopulateSources(tool.Tool, ManagedWindow):
    """
    Tool that populates the database with sources and citations.
    """

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = 'Populate sources and citations tool'
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')
        tool.Tool.__init__(self, dbstate, options_class, name)

        dialog = self.display()
        response = dialog.run()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            self.on_ok_clicked()
            OkDialog('Data generated',
                     "The requested sources and citations were generated",
                     parent=uistate.window)

        self.close()

    def display(self):
        """
        Constructs the GUI, consisting of a message, and fields to enter the
        required number of sources and citations
        """

        # retrieve options
        num_sources = self.options.handler.options_dict['sources']
        num_citations = self.options.handler.options_dict['citations']

        # GUI setup:
        dialog = Gtk.Dialog("Populate sources and citations tool",
                                self.uistate.window,
                                Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                (_('_Cancel'), Gtk.ResponseType.REJECT,
                                 _('_OK'), Gtk.ResponseType.ACCEPT))
        label = Gtk.Label("Enter a valid number of sources and citations."
                          " This will create the requested number of sources,"
                          " and for each source, will create the requested"
                          " number of citations.")
        label.set_line_wrap(True)

        hbox1 = Gtk.Box()
        label_sources = Gtk.Label(label="Number of sources" + ":")
        self.sources_entry = Gtk.Entry()
        self.sources_entry.set_text("%d" % num_sources)
        hbox1.pack_start(label_sources, False, True, 0)
        hbox1.pack_start(self.sources_entry, True, True, 0)

        hbox2 = Gtk.Box()
        label_citations = Gtk.Label(label="Number of citations" + ":")
        self.citations_entry = Gtk.Entry()
        self.citations_entry.set_text("%d" % num_citations)
        hbox2.pack_start(label_citations, False, True, 0)
        hbox2.pack_start(self.citations_entry, True, True, 0)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.pack_start(label, True, True, 0)
        vbox.pack_start(hbox1, False, True, 0)
        vbox.pack_start(hbox2, False, True, 0)

        dialog.vbox.set_spacing(10)
        dialog.vbox.pack_start(vbox, True, True, 0)
        dialog.show_all()
        return dialog

    def on_ok_clicked(self):
        """
        Method that is run when you click the OK button. The numbers of sources
        and citations are retrieved from the entry box and used to govern the
        amount of data generated
        """

        num_sources_text = self.sources_entry.get_text()
        try:
            num_sources = int(num_sources_text)
        except:
            return
        num_citations_text = self.citations_entry.get_text()
        num_citations = int(num_citations_text)

        self.progress = ProgressMeter(
            'Generating data', '', parent=self.uistate.window)
        self.progress.set_pass('Generating data',
                               num_sources*num_citations)
        LOG.debug("sources %04d citations %04d" % (num_sources,
                                                     num_citations))

        source = Source()
        citation = Citation()

        self.db.disable_signals()
        with DbTxn('Populate sources and citations', self.db) as trans:
            for i in range(num_sources):
                source.gramps_id = None
                source.handle = None
                source.title = "Source %04d" % (i + 1)
                source_handle = self.db.add_source(source, trans)

                for j in range(num_citations):
                    citation.gramps_id = None
                    citation.handle = None
                    citation.source_handle = source_handle
                    citation.page = "Page %04d" % (j + 1)
                    self.db.add_citation(citation, trans)
                    self.progress.step()
            LOG.debug("sources and citations added")
        self.db.enable_signals()
        self.db.request_rebuild()
        self.progress.close()

        self.options.handler.options_dict['sources'] = num_sources
        self.options.handler.options_dict['citations'] = num_citations
        # Save options
        self.options.handler.save_options()
Exemple #36
0
class PopulateSources(tool.Tool, ManagedWindow):
    """
    Gramplet that populates the database with sources and citations.
    """
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = 'Populate sources and citations tool'
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')
        tool.Tool.__init__(self, dbstate, options_class, name)

        dialog = self.display()
        response = dialog.run()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            self.on_ok_clicked()
            OkDialog('Data generated',
                     "The requested sources and citations were generated")

        self.close()

    def display(self):
        """
        Constructs the GUI, consisting of a message, and fields to enter the
        required number of sources and citations
        """

        # retrieve options
        num_sources = self.options.handler.options_dict['sources']
        num_citations = self.options.handler.options_dict['citations']

        # GUI setup:
        dialog = Gtk.Dialog(
            "Populate sources and citations tool", self.uistate.window,
            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK,
             Gtk.ResponseType.ACCEPT))
        label = Gtk.Label("Enter a valid number of sources and citations."
                          " This will create the requested number of sources,"
                          " and for each source, will create the requested"
                          " number of citations.")
        label.set_line_wrap(True)

        hbox1 = Gtk.HBox()
        label_sources = Gtk.Label(label="Number of sources" + ":")
        self.sources_entry = Gtk.Entry()
        self.sources_entry.set_text("%d" % num_sources)
        hbox1.pack_start(label_sources, False, True, 0)
        hbox1.pack_start(self.sources_entry, True, True, 0)

        hbox2 = Gtk.HBox()
        label_citations = Gtk.Label(label="Number of citations" + ":")
        self.citations_entry = Gtk.Entry()
        self.citations_entry.set_text("%d" % num_citations)
        hbox2.pack_start(label_citations, False, True, 0)
        hbox2.pack_start(self.citations_entry, True, True, 0)

        vbox = Gtk.VBox()
        vbox.pack_start(label, True, True, 0)
        vbox.pack_start(hbox1, False, True, 0)
        vbox.pack_start(hbox2, False, True, 0)

        dialog.vbox.set_spacing(10)
        dialog.vbox.pack_start(vbox, True, True, 0)
        dialog.show_all()
        return dialog

    def on_ok_clicked(self):
        """
        Method that is run when you click the OK button. The numbers of sources
        and citations are retrieved from the entry box and used to govern the
        amount of data generated
        """

        num_sources_text = self.sources_entry.get_text()
        try:
            num_sources = int(num_sources_text)
        except:
            return
        num_citations_text = self.citations_entry.get_text()
        num_citations = int(num_citations_text)

        self.progress = ProgressMeter('Generating data', '')
        self.progress.set_pass('Generating data', num_sources * num_citations)
        LOG.debug("sources %04d citations %04d" % (num_sources, num_citations))

        source = Source()
        citation = Citation()

        self.db.disable_signals()
        with DbTxn('Populate sources and citations', self.db) as trans:
            for i in range(num_sources):
                source.gramps_id = None
                source.handle = None
                source.title = "Source %04d" % (i + 1)
                source_handle = self.db.add_source(source, trans)

                for j in range(num_citations):
                    citation.gramps_id = None
                    citation.handle = None
                    citation.source_handle = source_handle
                    citation.page = "Page %04d" % (j + 1)
                    self.db.add_citation(citation, trans)
                    self.progress.step()
            LOG.debug("sources and citations added")
        self.db.enable_signals()
        self.db.request_rebuild()
        self.progress.close()

        self.options.handler.options_dict['sources'] = num_sources
        self.options.handler.options_dict['citations'] = num_citations
        # Save options
        self.options.handler.save_options()
Exemple #37
0
class DuplicatePeopleTool(tool.Tool, ManagedWindow):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        tool.Tool.__init__(self, dbstate, options_class, name)
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.uistate = uistate
        self.map = {}
        self.list = []
        self.index = 0
        self.merger = None
        self.mergee = None
        self.removed = {}
        self.update = callback
        self.use_soundex = 1

        top = Glade(toplevel="finddupes", also_load=["liststore1"])

        # retrieve options
        threshold = self.options.handler.options_dict['threshold']
        use_soundex = self.options.handler.options_dict['soundex']

        my_menu = Gtk.ListStore(str, object)
        for val in sorted(_val2label):
            my_menu.append([_val2label[val], val])

        self.soundex_obj = top.get_object("soundex")
        self.soundex_obj.set_active(use_soundex)
        self.soundex_obj.show()

        self.menu = top.get_object("menu")
        self.menu.set_model(my_menu)
        self.menu.set_active(0)

        window = top.toplevel
        self.set_window(window, top.get_object('title'),
                        _('Find Possible Duplicate People'))
        self.setup_configs('interface.duplicatepeopletool', 350, 220)

        top.connect_signals({
            "on_do_merge_clicked": self.__dummy,
            "on_help_show_clicked": self.__dummy,
            "on_delete_show_event": self.__dummy,
            "on_merge_ok_clicked": self.on_merge_ok_clicked,
            "destroy_passed_object": self.close,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_merge_event": self.close,
            "on_delete_event": self.close,
        })

        self.show()

    def build_menu_names(self, obj):
        return (_("Tool settings"), _("Find Duplicates tool"))

    def on_help_clicked(self, obj):
        """Display the relevant portion of Gramps manual"""

        display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC)

    def ancestors_of(self, p1_id, id_list):
        if (not p1_id) or (p1_id in id_list):
            return
        id_list.append(p1_id)
        p1 = self.db.get_person_from_handle(p1_id)
        f1_id = p1.get_main_parents_family_handle()
        if f1_id:
            f1 = self.db.get_family_from_handle(f1_id)
            self.ancestors_of(f1.get_father_handle(), id_list)
            self.ancestors_of(f1.get_mother_handle(), id_list)

    def on_merge_ok_clicked(self, obj):
        threshold = self.menu.get_model()[self.menu.get_active()][1]
        self.use_soundex = int(self.soundex_obj.get_active())
        try:
            self.find_potentials(threshold)
        except AttributeError as msg:
            RunDatabaseRepair(str(msg), parent=self.window)
            return

        self.options.handler.options_dict['threshold'] = threshold
        self.options.handler.options_dict['soundex'] = self.use_soundex
        # Save options
        self.options.handler.save_options()

        if len(self.map) == 0:
            OkDialog(_("No matches found"),
                     _("No potential duplicate people were found"),
                     parent=self.window)
        else:
            try:
                DuplicatePeopleToolMatches(self.dbstate, self.uistate,
                                           self.track, self.list, self.map,
                                           self.update)
            except WindowActiveError:
                pass

    def find_potentials(self, thresh):
        self.progress = ProgressMeter(_('Find Duplicates'),
                                      _('Looking for duplicate people'),
                                      parent=self.window)

        index = 0
        males = {}
        females = {}
        self.map = {}

        length = self.db.get_number_of_people()

        self.progress.set_pass(_('Pass 1: Building preliminary lists'), length)

        for p1_id in self.db.iter_person_handles():
            self.progress.step()
            p1 = self.db.get_person_from_handle(p1_id)
            key = self.gen_key(get_surnames(p1.get_primary_name()))
            if p1.get_gender() == Person.MALE:
                if key in males:
                    males[key].append(p1_id)
                else:
                    males[key] = [p1_id]
            else:
                if key in females:
                    females[key].append(p1_id)
                else:
                    females[key] = [p1_id]

        self.progress.set_pass(_('Pass 2: Calculating potential matches'),
                               length)

        for p1key in self.db.iter_person_handles():
            self.progress.step()
            p1 = self.db.get_person_from_handle(p1key)

            key = self.gen_key(get_surnames(p1.get_primary_name()))
            if p1.get_gender() == Person.MALE:
                remaining = males[key]
            else:
                remaining = females[key]

            #index = 0
            for p2key in remaining:
                #index += 1
                if p1key == p2key:
                    continue
                p2 = self.db.get_person_from_handle(p2key)
                if p2key in self.map:
                    (v, c) = self.map[p2key]
                    if v == p1key:
                        continue

                chance = self.compare_people(p1, p2)
                if chance >= thresh:
                    if p1key in self.map:
                        val = self.map[p1key]
                        if val[1] > chance:
                            self.map[p1key] = (p2key, chance)
                    else:
                        self.map[p1key] = (p2key, chance)

        self.list = sorted(self.map)
        self.length = len(self.list)
        self.progress.close()

    def gen_key(self, val):
        if self.use_soundex:
            try:
                return soundex(val)
            except UnicodeEncodeError:
                return val
        else:
            return val

    def compare_people(self, p1, p2):

        name1 = p1.get_primary_name()
        name2 = p2.get_primary_name()

        chance = self.name_match(name1, name2)
        if chance == -1:
            return -1

        birth1_ref = p1.get_birth_ref()
        if birth1_ref:
            birth1 = self.db.get_event_from_handle(birth1_ref.ref)
        else:
            birth1 = Event()

        death1_ref = p1.get_death_ref()
        if death1_ref:
            death1 = self.db.get_event_from_handle(death1_ref.ref)
        else:
            death1 = Event()

        birth2_ref = p2.get_birth_ref()
        if birth2_ref:
            birth2 = self.db.get_event_from_handle(birth2_ref.ref)
        else:
            birth2 = Event()

        death2_ref = p2.get_death_ref()
        if death2_ref:
            death2 = self.db.get_event_from_handle(death2_ref.ref)
        else:
            death2 = Event()

        value = self.date_match(birth1.get_date_object(),
                                birth2.get_date_object())
        if value == -1:
            return -1
        chance += value

        value = self.date_match(death1.get_date_object(),
                                death2.get_date_object())
        if value == -1:
            return -1
        chance += value

        value = self.place_match(birth1.get_place_handle(),
                                 birth2.get_place_handle())
        if value == -1:
            return -1
        chance += value

        value = self.place_match(death1.get_place_handle(),
                                 death2.get_place_handle())
        if value == -1:
            return -1
        chance += value

        ancestors = []
        self.ancestors_of(p1.get_handle(), ancestors)
        if p2.get_handle() in ancestors:
            return -1

        ancestors = []
        self.ancestors_of(p2.get_handle(), ancestors)
        if p1.get_handle() in ancestors:
            return -1

        f1_id = p1.get_main_parents_family_handle()
        f2_id = p2.get_main_parents_family_handle()

        if f1_id and f2_id:
            f1 = self.db.get_family_from_handle(f1_id)
            f2 = self.db.get_family_from_handle(f2_id)
            dad1_id = f1.get_father_handle()
            if dad1_id:
                dad1 = get_name_obj(self.db.get_person_from_handle(dad1_id))
            else:
                dad1 = None
            dad2_id = f2.get_father_handle()
            if dad2_id:
                dad2 = get_name_obj(self.db.get_person_from_handle(dad2_id))
            else:
                dad2 = None

            value = self.name_match(dad1, dad2)

            if value == -1:
                return -1

            chance += value

            mom1_id = f1.get_mother_handle()
            if mom1_id:
                mom1 = get_name_obj(self.db.get_person_from_handle(mom1_id))
            else:
                mom1 = None
            mom2_id = f2.get_mother_handle()
            if mom2_id:
                mom2 = get_name_obj(self.db.get_person_from_handle(mom2_id))
            else:
                mom2 = None

            value = self.name_match(mom1, mom2)
            if value == -1:
                return -1

            chance += value

        for f1_id in p1.get_family_handle_list():
            f1 = self.db.get_family_from_handle(f1_id)
            for f2_id in p2.get_family_handle_list():
                f2 = self.db.get_family_from_handle(f2_id)
                if p1.get_gender() == Person.FEMALE:
                    father1_id = f1.get_father_handle()
                    father2_id = f2.get_father_handle()
                    if father1_id and father2_id:
                        if father1_id == father2_id:
                            chance += 1
                        else:
                            father1 = self.db.get_person_from_handle(
                                father1_id)
                            father2 = self.db.get_person_from_handle(
                                father2_id)
                            fname1 = get_name_obj(father1)
                            fname2 = get_name_obj(father2)
                            value = self.name_match(fname1, fname2)
                            if value != -1:
                                chance += value
                else:
                    mother1_id = f1.get_mother_handle()
                    mother2_id = f2.get_mother_handle()
                    if mother1_id and mother2_id:
                        if mother1_id == mother2_id:
                            chance += 1
                        else:
                            mother1 = self.db.get_person_from_handle(
                                mother1_id)
                            mother2 = self.db.get_person_from_handle(
                                mother2_id)
                            mname1 = get_name_obj(mother1)
                            mname2 = get_name_obj(mother2)
                            value = self.name_match(mname1, mname2)
                            if value != -1:
                                chance += value
        return chance

    def name_compare(self, s1, s2):
        if self.use_soundex:
            try:
                return compare(s1, s2)
            except UnicodeEncodeError:
                return s1 == s2
        else:
            return s1 == s2

    def date_match(self, date1, date2):
        if date1.is_empty() or date2.is_empty():
            return 0
        if date1.is_equal(date2):
            return 1

        if date1.is_compound() or date2.is_compound():
            return self.range_compare(date1, date2)

        if date1.get_year() == date2.get_year():
            if date1.get_month() == date2.get_month():
                return 0.75
            if not date1.get_month_valid() or not date2.get_month_valid():
                return 0.75
            else:
                return -1
        else:
            return -1

    def range_compare(self, date1, date2):
        start_date_1 = date1.get_start_date()[0:3]
        start_date_2 = date2.get_start_date()[0:3]
        stop_date_1 = date1.get_stop_date()[0:3]
        stop_date_2 = date2.get_stop_date()[0:3]
        if date1.is_compound() and date2.is_compound():
            if (start_date_2 <= start_date_1 <= stop_date_2
                    or start_date_1 <= start_date_2 <= stop_date_1
                    or start_date_2 <= stop_date_1 <= stop_date_2
                    or start_date_1 <= stop_date_2 <= stop_date_1):
                return 0.5
            else:
                return -1
        elif date2.is_compound():
            if start_date_2 <= start_date_1 <= stop_date_2:
                return 0.5
            else:
                return -1
        else:
            if start_date_1 <= start_date_2 <= stop_date_1:
                return 0.5
            else:
                return -1

    def name_match(self, name, name1):

        if not name1 or not name:
            return 0

        srn1 = get_surnames(name)
        sfx1 = name.get_suffix()
        srn2 = get_surnames(name1)
        sfx2 = name1.get_suffix()

        if not self.name_compare(srn1, srn2):
            return -1
        if sfx1 != sfx2:
            if sfx1 != "" and sfx2 != "":
                return -1

        if name.get_first_name() == name1.get_first_name():
            return 1
        else:
            list1 = name.get_first_name().split()
            list2 = name1.get_first_name().split()

            if len(list1) < len(list2):
                return self.list_reduce(list1, list2)
            else:
                return self.list_reduce(list2, list1)

    def place_match(self, p1_id, p2_id):
        if p1_id == p2_id:
            return 1

        if not p1_id:
            name1 = ""
        else:
            p1 = self.db.get_place_from_handle(p1_id)
            name1 = p1.get_title()

        if not p2_id:
            name2 = ""
        else:
            p2 = self.db.get_place_from_handle(p2_id)
            name2 = p2.get_title()

        if not (name1 and name2):
            return 0
        if name1 == name2:
            return 1

        list1 = name1.replace(",", " ").split()
        list2 = name2.replace(",", " ").split()

        value = 0
        for name in list1:
            for name2 in list2:
                if name == name2:
                    value += 0.5
                elif name[0] == name2[0] and self.name_compare(name, name2):
                    value += 0.25
        return min(value, 1) if value else -1

    def list_reduce(self, list1, list2):
        value = 0
        for name in list1:
            for name2 in list2:
                if is_initial(name) and name[0] == name2[0]:
                    value += 0.25
                elif is_initial(name2) and name2[0] == name[0]:
                    value += 0.25
                elif name == name2:
                    value += 0.5
                elif name[0] == name2[0] and self.name_compare(name, name2):
                    value += 0.25
        return min(value, 1) if value else -1

    def __dummy(self, obj):
        """dummy callback, needed because a shared glade file is used for
        both toplevel windows and all signals must be handled.
        """
        pass
Exemple #38
0
class PukReport(Report):
    """
    This report produces .
    """
    genderlist = ['w','m','u']
    def __init__(self, database, options, user):
        """
        Create the SourceReport object that produces the report.
        
        The arguments are:

        database        - the GRAMPS database instance
        options         - instance of the Options class for this report
        user            - a gen.user.User() instance

        This report needs the following parameters (class variables)
        that come in the options class.
        
        Sources          - List of places to report on.
        """

        Report.__init__(self, database, options, user)
        self.__db = database
        self._user = user
       
        menu = options.menu
        self.title_string = menu.get_option_by_name('title').get_value()
        self.subtitle_string = menu.get_option_by_name('subtitle').get_value()
        self.footer_string = menu.get_option_by_name('footer').get_value()
#        self.showpersons = menu.get_option_by_name('showpersons').get_value()
#        self.addimages     = menu.get_option_by_name('incphotos').get_value()

        menucalc = options.menu
#        self.title_string = menu.get_option_by_name('title').get_value()
#        self.subtitle_string = menu.get_option_by_name('subtitle').get_value()
#        self.footer_string = menu.get_option_by_name('footer').get_value()
        self.showallfamilies =menucalc.get_option_by_name('showallfamilies').get_value()
#        self.addimages     = menu.get_option_by_name('incphotos').get_value()
        
        self.pl_format  = menu.get_option_by_name('placeformat').get_value()


        filter_option = menucalc.get_option_by_name('filter')
        self.filter = filter_option.get_filter()
#        self.sort = Sort.Sort(self.database)

        if self.filter.get_name() != '':
            # Use the selected filter to provide a list of source handles
            sourcefilterlist = self.__db.iter_source_handles()
            self.source_handles = self.filter.apply(self.__db, sourcefilterlist)
        else:
            self.source_handles = self.__db.get_source_handles()



    def write_report(self):
        """
        Overridden function to generate the report.
        """
        self.progress = ProgressMeter(_("PUK Export"), '')
        self.doc.start_paragraph("SRC-ReportTitle")
        title = self.title_string
        mark = IndexMark(title, INDEX_TYPE_TOC, 1)  
        self.doc.write_text(title, mark)
        self.doc.end_paragraph()
        
        self.doc.start_paragraph("SRC-ReportTitle")
        title = self.subtitle_string
        mark = IndexMark(title, INDEX_TYPE_TOC, 1)  
        self.doc.write_text(title, mark)
        self.doc.end_paragraph()
        
        self.listpersonref()
        
        self.doc.start_paragraph('SRC-Footer')
        self.doc.write_text(self.footer_string)
        self.doc.end_paragraph()
        self.progress.close()

    def find_place(self, place_handle):
        placename = " "
        if place_handle:
            place =  self.__db.get_place_from_handle(place_handle)
            if place:
                placename = place.title
        return placename 

    def find_clan(self, person_handle):
        # returns a string composed of all surnames of her family  = clanname
        #
        family_list = []
        family_handle = None
        family_list = self.__db.get_person_from_handle(person_handle).get_family_handle_list()
        clanname =""
        if len(family_list) == 0:
            clanname =  self.__db.get_person_from_handle(person_handle).primary_name.get_surname()
        else:
            if self.showallfamilies:
                for fam in family_list:
                    if self.__db.get_family_from_handle(fam).get_father_handle():
                        clanname = clanname + self.__db.get_person_from_handle(self.__db.get_family_from_handle(fam).get_father_handle()).primary_name.get_surname()+" "
            else:
                if self.__db.get_family_from_handle(family_list[0]).get_father_handle():
                    clanname = self.__db.get_person_from_handle(self.__db.get_family_from_handle(family_list[0]).get_father_handle()).primary_name.get_surname()
        return clanname 

    def __format_date(self, date_object):
        if not date_object: return
        d=date_object.get_day()    
        m=date_object.get_month()
        y=date_object.get_year()
        if (d == 0) and (m == 0):
            date_f = (" %s" % y)
        elif (d == 0) and not (m == 0):
            date_f = (" %s/%s" % (m, y))  
        else:       
            date_f = (" %s/%s/%s" % (d, m, y)) 
        return date_f           
        
    def find_occupation(self, person):
        """
        Use the most recent occupation event.
        """
        occupationtxt = " "
        event_refs = person.get_primary_event_ref_list()
        events = [event for event in
                    [self.__db.get_event_from_handle(ref.ref) for ref in event_refs]
                    if event.get_type() == EventType(EventType.OCCUPATION)]
        if len(events) > 0:
            events.sort(key=lambda x: x.get_date_object())
#            print(events[0].get_description())
            occupation = events[-1].get_description()
            if occupation:
                occupationtxt=("%s" % occupation)
        return(occupationtxt)

    def listpersonref(self):

        sc = {'source': 'S_ID',
              'citalist': 'C_ID' }
        stc = {}      
        citation_without_notes = 0
        EMPTY = " "

        def toYear(date):
            yeartext = date.get_year()
            return yeartext         

        def toNbr(text):
            text = text[1:]
            while text[0] == "0":
                text = text[1:]
            return text         


        genderlist = ['F','M','X']
     # build citasource dictionary  and cl list 
        
        sc = defaultdict(list)
        cl = []
        i=1
        for ci in self.__db.iter_citations():
            if ci.source_handle in self.source_handles:
                sc[ci.source_handle].append(ci.handle)
                cl.append(ci.handle)

        # build citations - event dic                       xy
        #(a,b): set([('Citation', 'c4a8c46041e08799b17')]) 
        # event: c4a8c4f95b01e38564a event: Taufe
        ci = defaultdict(list)
        for ev in self.__db.iter_events():
            refhandlelist = ev.get_referenced_handles()   
            for (a,b) in refhandlelist:
                if a == 'Citation':
                    if b in cl:                    #!
                        ci[ev.handle].append(b)
        ci_evkeys = ci.keys()                

#***********************************************************************
#       # build godparentsdict of all persons
#

        gpdic ={}
        gpdic = defaultdict(list)
        for pe in self.__db.get_person_handles():
            for eventref in self.__db.get_person_from_handle(pe).event_ref_list:
                if not eventref.get_role().is_primary():
                    if eventref.get_role() == "Pate":
                        gpdic[eventref.ref].append((eventref.get_role(),pe))
        gpdickeys = gpdic.keys()

        for i in gpdic.keys():
            print(self.__db.get_event_from_handle(i).get_date_object())
            for (a,b) in gpdic[i]:
                print("TEIL     ",a
                        ,name_displayer.display(self.__db.get_person_from_handle(b))
                        ,self.__db.get_person_from_handle(b).gramps_id)
        print("GPDIC   ",len(gpdickeys))



#***********************************************************************
#       # build family list of all families with familyevent in citation
#
#       a    family handle
#
        famlist =[]
#        famdic = {}
        for fh in self.__db.get_family_handles():
            for eventref in self.__db.get_family_from_handle(fh).event_ref_list:
                if eventref.ref in ci_evkeys:
                    famlist.append(fh)
        # Each family only once
        famlist = list(set(famlist))
#        for fi,f in enumerate(famlist):
#            famdic[f]=fi

#***********************************************************************
#       # build pedic of all persons in families with familyevent in citation
#
#       k    gramps_id
#       v    1...n

        pedic ={}

        self.doc.start_paragraph("SRC-SourceTitle")
        self.doc.write_text(_("Person with Citations"))
        self.doc.end_paragraph()       

        indexlist = list()


        self.doc.start_table("Corpus Attributes", "SRC-VISONETable")
        name_list =["Zeile 1", "Zeile 2"]
        self.progress.set_pass(_('Start Table Corpus'), len(name_list))
        for nl in name_list:
            self.doc.start_row()
            self.doc.start_cell("SRC-TableColumn")
            self.doc.start_paragraph("SRC-ColumnTitle")
            self.doc.write_text(nl)
            self.doc.end_paragraph()
            self.doc.end_cell()
            self.doc.end_row()                 
        self.doc.end_table()


        self.progress.set_pass(_('Start Table Families'), len(famlist))

        self.doc.start_table("Families", "SRC-VISONETable")
##        column_titles = [_("Prim_ID"), _("Gramps_ID"),  _("Role"), _("Relation"), _("LNr"), _("Ev ID"),_("Event"), _("Date"), _("Year"), _("Age Primary"), _("Age Person"), _("gender Primary"), _("gender Person") , _("Person"),_("Primary"), _("Person birth"), _("Person Clan"),_("Primary Clan"),_("Event Place"),_("FamID"),_("AnzKind")] 
        column_titles = [_("Id"), "Status", "FatherId", "MotherId", "Children", "HUSB_ORD", "WIFE_ORD", _("Fam_ID"), _("Father_ID"), _("Mother_ID"), _("Children_ID")] 

        i = 0
        self.doc.start_row()
        for title in column_titles:
            self.doc.start_cell("SRC-TableColumn")
            self.doc.start_paragraph("SRC-ColumnTitle")
            self.doc.write_text(title)
            self.doc.end_paragraph()
            self.doc.end_cell()
        self.doc.end_row()                 
        i=0 
        ii=0
        

        fid = 0
        for f in sorted(famlist):
            famidtext = ""
            fathernametxt = ""
            mothernametxt = ""
            fatheridtxt = ""
            motheridtxt = ""
            childtxt = ""
            fatherordertxt = ""
            motherordertxt = ""
            
            family = self.__db.get_family_from_handle(f)
            famidtxt = (" [%s]" % family.gramps_id)
            famreltxt = family.get_relationship()
            if famreltxt == "Verheiratet":
                famreltxt = "M"
            elif famreltxt == "Unverheiratet":
#                print(famreltxt)
                famreltxt = " "
#                print("FAM    ",famreltxt)
            elif famreltxt == "Unbekannt":
                famreltxt = " "
            if family.get_father_handle():
                fathernametxt = fathernametxt + self.__db.get_person_from_handle(family.get_father_handle()).primary_name.get_name()
                famhandlelist = self.__db.get_person_from_handle(family.get_father_handle()).get_family_handle_list()
                fatherordertxt = ("%s" % len(famhandlelist))
                fatheridtxt = self.__db.get_person_from_handle(family.get_father_handle()).gramps_id
                indexlist.append(fatheridtxt)
                fatheridtxt = toNbr(fatheridtxt)

            if family.get_mother_handle():
                mothernametxt = mothernametxt + self.__db.get_person_from_handle(family.get_mother_handle()).primary_name.get_name()
                famhandlelist = self.__db.get_person_from_handle(family.get_mother_handle()).get_family_handle_list()
                motheridtxt = self.__db.get_person_from_handle(family.get_mother_handle()).gramps_id
                motherordertxt = ("%s" % len(famhandlelist))
                indexlist.append(motheridtxt)
                motheridtxt = toNbr(motheridtxt)
                # BUG only count not order
            childtxt =""
            for ch in family.get_child_ref_list():
                child = self.__db.get_person_from_handle(ch.ref)
                if child:
                    childtxt1 = child.get_gramps_id()
                    childtxt1 = childtxt1 + ";"
                    indexlist.append(child.get_gramps_id())
                    childtxt1 = toNbr(childtxt1)
                    childtxt = childtxt + childtxt1
            fid += 1
            line = []
            line.append(fid)
            line.append(famreltxt)
            line.append(fatheridtxt)
            line.append(motheridtxt)
            line.append(childtxt)
            line.append(fatherordertxt)
            line.append(motherordertxt) 
            line.append(famidtxt)
            line.append(fathernametxt)
            line.append(mothernametxt)


            self.doc.start_row()
            for l in line:
                self.doc.start_cell("SRC-Cell")
                self.doc.start_paragraph("SRC-SourceDetails")
                self.doc.write_text(_("%s") %
                                    l)
                self.doc.end_paragraph()
                self.doc.end_cell()
            self.doc.end_row()
            self.progress.step()

        self.doc.end_table()

        self.doc.start_table("Individuals", "SRC-VISONETable")
        column_titles = [_("Id"), "Name", "Gender", "ORD", "BIRT_DATE", "BIRT_PLACE", "DEAT_DATE", "DEAT_PLACE", "OCCU", "PersonID2"]
#   Id	Name	Gender	ORD	BIRT_DATE	Rolle	PersonID2


        i = 0
        self.doc.start_row()
        for title in column_titles:
            self.doc.start_cell("SRC-TableColumn")
            self.doc.start_paragraph("SRC-ColumnTitle")
            self.doc.write_text(title)
            self.doc.end_paragraph()
            self.doc.end_cell()
        self.doc.end_row()                 


        l = len(indexlist)
        indexlist = list(set(indexlist))

        self.progress.set_pass(_('Start Table Individuals'), len(indexlist))

#        for m in indexlist:
#            print(m)
        pi = 1
        for il in indexlist:
            self.doc.start_row()
            person = self.__db.get_person_from_gramps_id(il)
            

# Id
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                                toNbr(il))
            self.doc.end_paragraph()
            self.doc.end_cell()

# Name
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                                person.primary_name.get_gedcom_name())
            self.doc.end_paragraph()
            self.doc.end_cell()

# Gender
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                                    genderlist[person.get_gender()])
            self.doc.end_paragraph()
            self.doc.end_cell()

# Ord
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                                " ")
#                                person.primary_name.get_name())
            self.doc.end_paragraph()
            self.doc.end_cell()

# Birth Date
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            birth_ref = person.get_birth_ref()
            birth_date = None
            birthtxt = " "
            birthplacetxt = " "
            if birth_ref:
                birthtxt = self.__format_date(self.__db.get_event_from_handle(birth_ref.ref).get_date_object())
#                birthplacetxt = self.find_place(self.__db.get_event_from_handle(birth_ref.ref).place)
                birthplacetxt = place_displayer.display_event(self.__db, self.__db.get_event_from_handle(birth_ref.ref), self.pl_format)

            self.doc.write_text(_("%s") %
                                birthtxt)
            self.doc.end_paragraph()
            self.doc.end_cell()
            


# Place of Event
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                         birthplacetxt[4:-2])
            self.doc.end_paragraph()
            self.doc.end_cell()

# Death Date
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            death_ref = person.get_death_ref()
            death_date = None
            deathtxt = " "
            deathplacetxt = " "
            if death_ref:
                deathtxt = self.__format_date(self.__db.get_event_from_handle(death_ref.ref).get_date_object())
                deathplacetxt = place_displayer.display_event(self.__db, self.__db.get_event_from_handle(death_ref.ref), self.pl_format)
            self.doc.write_text(_("%s") %
                                deathtxt)
            self.doc.end_paragraph()
            self.doc.end_cell()


# Place of Event
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                         deathplacetxt[4:-2])
            self.doc.end_paragraph()
            self.doc.end_cell()


# Occupation
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                         self.find_occupation(person))
            self.doc.end_paragraph()
            self.doc.end_cell()


# Person_ID
            self.doc.start_cell("SRC-Cell")
            self.doc.start_paragraph("SRC-SourceDetails")
            self.doc.write_text(_("%s") %
                                il)
            self.doc.end_paragraph()
            self.doc.end_cell()


            self.doc.end_row()
            pi += 1

        print (l,len(indexlist))
        self.progress.step()
        self.doc.end_table()

        self.progress.set_pass(_('Start Table Relation'), len(indexlist))

        self.doc.start_table("Relation", "SRC-VISONETable")
        column_titles = [_("Id"), "Name", "Candidate", "Godparent", "#DATE"]
#_("Id"), "Name", "Candidate", "Godparent", "#DATE"
#
#
        self.doc.start_row()
        self.doc.start_cell("SRC-TableColumn")
        self.doc.start_paragraph("SRC-ColumnTitle")
        self.doc.write_text("Patenschaften")
        self.doc.end_paragraph()
        self.doc.end_cell()
        self.doc.end_row()
#
        i = 0
        self.doc.start_row()
        for title in column_titles:
            self.doc.start_cell("SRC-TableColumn")
            self.doc.start_paragraph("SRC-ColumnTitle")
            self.doc.write_text(title)
            self.doc.end_paragraph()
            self.doc.end_cell()
        self.doc.end_row()


        l = len(indexlist)
        indexlist = list(set(indexlist))
#        for m in indexlist:
#            print(m)
        pi = 1
        for il in indexlist:
            person = self.__db.get_person_from_gramps_id(il)
            for eventref in person.get_event_ref_list():
                event = self.__db.get_event_from_handle(eventref.ref)
##                if event and event.type.is_baptism():
                if event.type.is_baptism():

                    self.doc.start_row()
# EventId
                    self.doc.start_cell("SRC-Cell")
                    self.doc.start_paragraph("SRC-SourceDetails")
                    self.doc.write_text(_("%s") %
                                        toNbr(event.gramps_id))
                    self.doc.end_paragraph()
                    self.doc.end_cell()

# Name
                    self.doc.start_cell("SRC-Cell")
                    self.doc.start_paragraph("SRC-SourceDetails")
                    self.doc.write_text(_("Bapt %s") %
                                        event.get_description())
                    self.doc.end_paragraph()
                    self.doc.end_cell()

# Candidate
                    self.doc.start_cell("SRC-Cell")
                    self.doc.start_paragraph("SRC-SourceDetails")
                    self.doc.write_text(_("%s") %
                                        toNbr(il))
                    self.doc.end_paragraph()
                    self.doc.end_cell()

# Godparents


                    patentxt =""
                    for i in gpdickeys:
                        if self.__db.get_event_from_handle(i).gramps_id == event.gramps_id:
                            for (a,b) in gpdic[i]:
                                patentxt = patentxt + toNbr(self.__db.get_person_from_handle(b).gramps_id) +";"

                    self.doc.start_cell("SRC-Cell")
                    self.doc.start_paragraph("SRC-SourceDetails")
                    self.doc.write_text(_("%s") %
                                        patentxt)
                    self.doc.end_paragraph()
                    self.doc.end_cell()


# Date
                    self.doc.start_cell("SRC-Cell")
                    self.doc.start_paragraph("SRC-SourceDetails")
                    self.doc.write_text(_(" %s") %
                                 self.__format_date(event.get_date_object()))
                    self.doc.end_paragraph()
                    self.doc.end_cell()
                    self.doc.end_row()
                    pi += 1
            self.progress.step()
        print (l,len(indexlist))
        self.doc.end_table()
Exemple #39
0
    def _createmap(self, place_x):
        """
        Create all markers for each people's event in the database which has
        a lat/lon.
        """
        dbstate = self.dbstate
        self.place_list = []
        self.places_found = []
        self.place_without_coordinates = []
        self.minlat = 0.0
        self.maxlat = 0.0
        self.minlon = 0.0
        self.maxlon = 0.0
        self.minyear = 9999
        self.maxyear = 0
        self.without = 0
        latitude = ""
        longitude = ""
        self.nbmarkers = 0
        self.nbplaces = 0
        self.remove_all_markers()
        self.message_layer.clear_messages()
        self.message_layer.clear_font_attributes()
        self.kml_layer.clear()
        self.no_show_places_in_status_bar = False
        _col = self._config.get
        self.plc_color  = [
            (PlaceType.UNKNOWN, _col('geography.color.unknown')),
            (PlaceType.CUSTOM, _col('geography.color.custom')),
            (PlaceType.COUNTRY, _col('geography.color.country')),
            (PlaceType.STATE, _col('geography.color.state')),
            (PlaceType.COUNTY, _col('geography.color.county')),
            (PlaceType.CITY, _col('geography.color.city')),
            (PlaceType.PARISH, _col('geography.color.parish')),
            (PlaceType.LOCALITY, _col('geography.color.locality')),
            (PlaceType.STREET, _col('geography.color.street')),
            (PlaceType.PROVINCE, _col('geography.color.province')),
            (PlaceType.REGION, _col('geography.color.region')),
            (PlaceType.DEPARTMENT, _col('geography.color.department')),
            (PlaceType.NEIGHBORHOOD, _col('geography.color.neighborhood')),
            (PlaceType.DISTRICT, _col('geography.color.district')),
            (PlaceType.BOROUGH, _col('geography.color.borough')),
            (PlaceType.MUNICIPALITY, _col('geography.color.municipality')),
            (PlaceType.TOWN, _col('geography.color.town')),
            (PlaceType.VILLAGE, _col('geography.color.village')),
            (PlaceType.HAMLET, _col('geography.color.hamlet')),
            (PlaceType.FARM, _col('geography.color.farm')),
            (PlaceType.BUILDING, _col('geography.color.building')),
            (PlaceType.NUMBER, _col('geography.color.number'))
            ]
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 1'23"
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization
        # base "villes de france" : 38101 places :
        # gramps 3.4 python 2.7 (draw_markers are estimated when moving the map)
        # 38101 places: createmap: 04'32";
        #               create_markers: 0'04"; draw markers: N/A :: 0'03"
        # 65598 places: createmap: 10'03";
        #               create_markers: 0'07"; draw markers: N/A :: 0'05"
        # gramps 3.5 python 2.7 new marker layer
        # 38101 places: createmap: 03'09";
        #               create_markers: 0'01"; draw markers: 0'04"
        # 65598 places: createmap: 08'48";
        #               create_markers: 0'01"; draw markers: 0'07"
        _LOG.debug("%s", time.strftime("start createmap : "
                   "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.show_all:
            self.show_all = False
            try:
                places_handle = dbstate.db.get_place_handles()
            except:
                return
            progress = ProgressMeter(self.window_name,
                                     can_cancel=False,
                                     parent=self.uistate.window)
            length = len(places_handle)
            progress.set_pass(_('Selecting all places'), length)
            for place_hdl in places_handle:
                place = dbstate.db.get_place_from_handle(place_hdl)
                self._create_one_place(place)
                progress.step()
            progress.close()
        elif self.generic_filter:
            user=self.uistate.viewmanager.user
            place_list = self.generic_filter.apply(dbstate.db, user=user)
            progress = ProgressMeter(self.window_name,
                                     can_cancel=False,
                                     parent=self.uistate.window)
            length = len(place_list)
            progress.set_pass(_('Selecting all places'), length)
            for place_handle in place_list:
                place = dbstate.db.get_place_from_handle(place_handle)
                self._create_one_place(place)
                progress.step()
            progress.close()
            # reset completely the filter. It will be recreated next time.
            self.generic_filter = None
        elif place_x != None:
            place = dbstate.db.get_place_from_handle(place_x)
            self._create_one_place(place)
            self.message_layer.add_message(
                 _("Right click on the map and select 'show all places'"
                   " to show all known places with coordinates. "
                   "You can change the markers color depending on place type. "
                   "You can use filtering."))
            if place.get_latitude() != "" and place.get_longitude() != "":
                latitude, longitude = conv_lat_lon(place.get_latitude(),
                                                   place.get_longitude(),
                                                   "D.D8")
                self.osm.set_center_and_zoom(float(latitude), float(longitude),
                                             int(config.get(
                                                 "geography.zoom_when_center")))
        else:
            self.message_layer.add_message(
                 _("Right click on the map and select 'show all places'"
                   " to show all known places with coordinates. "
                   "You can use the history to navigate on the map. "
                   "You can change the markers color depending on place type. "
                   "You can use filtering."))
        _LOG.debug(" stop createmap.")
        _LOG.debug("%s", time.strftime("begin sort : "
                   "%a %d %b %Y %H:%M:%S", time.gmtime()))
        self.sort = sorted(self.place_list,
                           key=operator.itemgetter(0)
                          )
        _LOG.debug("%s", time.strftime("  end sort : "
                   "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.nbmarkers > 500: # performance issue. Is it the good value ?
            self.message_layer.add_message(
                 _("The place name in the status bar is disabled."))
            self.no_show_places_in_status_bar = True
        if self.nbplaces >= self._config.get("geography.max_places"):
            self.message_layer.set_font_attributes(None, None, "red")
            self.message_layer.add_message(
                 _("The maximum number of places is reached (%d).") %
                   self._config.get("geography.max_places"))
            self.message_layer.add_message(
                 _("Some information are missing."))
            self.message_layer.add_message(
                 _("Please, use filtering to reduce this number."))
            self.message_layer.add_message(
                 _("You can modify this value in the geography option."))
            self.message_layer.add_message(
                 _("In this case, it may take time to show all markers."))

        self._create_markers()
Exemple #40
0
    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_objects()
        progress.set_pass(_('Checking paths'), length)

        in_gramps = []
        for handle in self.db.get_media_object_handles():
            handle = handle.decode('utf-8')
            media = self.db.get_object_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()
class DateParserDisplayTest(tool.Tool):

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        tool.Tool.__init__(self, dbstate, options_class, name)
        if uistate:
            # Running with gui -> Show message
            self.parent_window = uistate.window
            QuestionDialog(_("Start date test?"),
                _("This test will create many persons and events " \
                    "in the current database. Do you really want to " \
                    "run this test?"),
                _("Run test"),
                self.run_tool,
                parent=self.parent_window)
        else:
            self.parent_window = None
            self.run_tool()


    def run_tool(self):
        self.progress = ProgressMeter(_('Running Date Test'),'',
                                        parent=self.parent_window)
        self.progress.set_pass(_('Generating dates'),
                               4)
        dates = []
        # first some valid dates
        calendar = Date.CAL_GREGORIAN
        for quality in (Date.QUAL_NONE, Date.QUAL_ESTIMATED,
                        Date.QUAL_CALCULATED):
            for modifier in (Date.MOD_NONE, Date.MOD_BEFORE,
                             Date.MOD_AFTER, Date.MOD_ABOUT):
                for slash1 in (False,True):
                    for month in range(0,13):
                        for day in (0,5,27):
                            if not month and day:
                                continue
                            d = Date()
                            d.set(quality,modifier,calendar,(day,month,1789,slash1),"Text comment")
                            dates.append( d)
            for modifier in (Date.MOD_RANGE, Date.MOD_SPAN):
                for slash1 in (False,True):
                    for slash2 in (False,True):
                        for month in range(0,13):
                            for day in (0,5,27):
                                if not month and day:
                                    continue

                                d = Date()
                                d.set(quality,modifier,calendar,(day,month,1789,slash1,day,month,1876,slash2),"Text comment")
                                dates.append( d)

                                if not month:
                                    continue

                                d = Date()
                                d.set(quality,modifier,calendar,(day,month,1789,slash1,day,13-month,1876,slash2),"Text comment")
                                dates.append( d)

                                if not day:
                                    continue

                                d = Date()
                                d.set(quality,modifier,calendar,(day,month,1789,slash1,32-day,month,1876,slash2),"Text comment")
                                dates.append( d)
                                d = Date()
                                d.set(quality,modifier,calendar,(day,month,1789,slash1,32-day,13-month,1876,slash2),"Text comment")
                                dates.append( d)
            modifier = Date.MOD_TEXTONLY
            d = Date()
            d.set(quality,modifier,calendar,Date.EMPTY,
                  "This is a textual date")
            dates.append( d)
            self.progress.step()
        
        # test invalid dates
        #dateval = (4,7,1789,False,5,8,1876,False)
        #for l in range(1,len(dateval)):
        #    d = Date()
        #    try:
        #        d.set(Date.QUAL_NONE,Date.MOD_NONE,
        #              Date.CAL_GREGORIAN,dateval[:l],"Text comment")
        #        dates.append( d)
        #    except DateError, e:
        #        d.set_as_text("Date identified value correctly as invalid.\n%s" % e)
        #        dates.append( d)
        #    except:
        #        d = Date()
        #        d.set_as_text("Date.set Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
        #        dates.append( d)
        #for l in range(1,len(dateval)):
        #    d = Date()
        #    try:
        #        d.set(Date.QUAL_NONE,Date.MOD_SPAN,Date.CAL_GREGORIAN,dateval[:l],"Text comment")
        #        dates.append( d)
        #    except DateError, e:
        #        d.set_as_text("Date identified value correctly as invalid.\n%s" % e)
        #        dates.append( d)
        #    except:
        #        d = Date()
        #        d.set_as_text("Date.set Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
        #        dates.append( d)
        #self.progress.step()
        #d = Date()
        #d.set(Date.QUAL_NONE,Date.MOD_NONE,
        #      Date.CAL_GREGORIAN,(44,7,1789,False),"Text comment")
        #dates.append( d)
        #d = Date()
        #d.set(Date.QUAL_NONE,Date.MOD_NONE,
        #      Date.CAL_GREGORIAN,(4,77,1789,False),"Text comment")
        #dates.append( d)
        #d = Date()
        #d.set(Date.QUAL_NONE,Date.MOD_SPAN,
        #      Date.CAL_GREGORIAN,
        #      (4,7,1789,False,55,8,1876,False),"Text comment")
        #dates.append( d)
        #d = Date()
        #d.set(Date.QUAL_NONE,Date.MOD_SPAN,
        #      Date.CAL_GREGORIAN,
        #      (4,7,1789,False,5,88,1876,False),"Text comment")
        #dates.append( d)
        
        with DbTxn(_("Date Test Plugin"), self.db, batch=True) as self.trans:
            self.db.disable_signals()
            self.progress.set_pass(_('Generating dates'),
                                   len(dates))

            # create pass and fail tags
            pass_handle = self.create_tag(_('Pass'), '#0000FFFF0000')
            fail_handle = self.create_tag(_('Fail'), '#FFFF00000000')

            # now add them as birth to new persons
            i = 1
            for dateval in dates:
                person = Person()
                surname = Surname()
                surname.set_surname("DateTest")
                name = Name()
                name.add_surname(surname)
                name.set_first_name("Test %d" % i)
                person.set_primary_name(name)
                self.db.add_person(person, self.trans)
                bevent = Event()
                bevent.set_type(EventType.BIRTH)
                bevent.set_date_object(dateval)
                bevent.set_description("Date Test %d (source)" % i)
                bevent_h = self.db.add_event(bevent, self.trans)
                bevent_ref = EventRef()
                bevent_ref.set_reference_handle(bevent_h)
                # for the death event display the date as text and parse it back to a new date
                ndate = None
                try:
                    datestr = _dd.display( dateval)
                    try:
                        ndate = _dp.parse( datestr)
                        if not ndate:
                            ndate = Date()
                            ndate.set_as_text("DateParser None")
                            person.add_tag(fail_handle)
                        else:
                            person.add_tag(pass_handle)
                    except:
                        ndate = Date()
                        ndate.set_as_text("DateParser Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
                        person.add_tag(fail_handle)
                    else:
                        person.add_tag(pass_handle)
                except:
                    ndate = Date()
                    ndate.set_as_text("DateDisplay Exception: %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
                    person.add_tag(fail_handle)
                
                if dateval.get_modifier() != Date.MOD_TEXTONLY \
                       and ndate.get_modifier() == Date.MOD_TEXTONLY:
                    # parser was unable to correctly parse the string
                    ndate.set_as_text( "TEXTONLY: "+ndate.get_text())
                    person.add_tag(fail_handle)
                if dateval.get_modifier() == Date.MOD_TEXTONLY \
                        and dateval.get_text().count("Traceback") \
                        and pass_handle in person.get_tag_list():
                    person.add_tag(fail_handle)
                
                devent = Event()
                devent.set_type(EventType.DEATH)
                devent.set_date_object(ndate)
                devent.set_description("Date Test %d (result)" % i)
                devent_h = self.db.add_event(devent, self.trans)
                devent_ref = EventRef()
                devent_ref.set_reference_handle(devent_h)
                person.set_birth_ref(bevent_ref)
                person.set_death_ref(devent_ref)
                self.db.commit_person(person, self.trans)
                i = i + 1
                self.progress.step()
        self.db.enable_signals()
        self.db.request_rebuild()
        self.progress.close()

    def create_tag(self, tag_name, tag_color):
        """
        Create a tag if it doesn't already exist.
        """
        tag = self.db.get_tag_from_name(tag_name)
        if tag is None:
            tag = Tag()
            tag.set_name(tag_name)
            if tag_color is not None:
                tag.set_color(tag_color)
            tag.set_priority(self.db.get_number_of_tags())
            tag_handle = self.db.add_tag(tag, self.trans)
        else:
            tag_handle = tag.get_handle()
        return tag_handle
class BirthOrder(tool.Tool, ManagedWindow):
    """ Sort children in a fmily in the order of birth """
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        tool.Tool.__init__(self, dbstate, options_class, name)
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.db = dbstate.db
        self.uistate = uistate
        self.map = {}
        self.list = []
        self.index = 0
        self.fam_h = self.fam_iter = self.family = self.progress = None
        self.update = callback

        self.top = Gtk.Builder()
        # Found out that Glade does not support translations for plugins, so
        # have to do it manually.
        base = os.path.dirname(__file__)
        glade_file = base + os.sep + "birthorder.glade"
        # This is needed to make gtk.Builder work by specifying the
        # translations directory in a separate 'domain'
        try:
            localedomain = "addon"
            localepath = base + os.sep + "locale"
            if hasattr(locale, 'bindtextdomain'):
                libintl = locale
            elif win():  # apparently wants strings in bytes
                localedomain = localedomain.encode('utf-8')
                localepath = localepath.encode('utf-8')
                libintl = ctypes.cdll.LoadLibrary('libintl-8.dll')
            else:  # mac, No way for author to test this
                libintl = ctypes.cdll.LoadLibrary('libintl.dylib')

            libintl.bindtextdomain(localedomain, localepath)
            libintl.textdomain(localedomain)
            libintl.bind_textdomain_codeset(localedomain, "UTF-8")
            # and finally, tell Gtk Builder to use that domain
            self.top.set_translation_domain("addon")
        except (OSError, AttributeError):
            # Will leave it in English
            print("Localization of BirthOrder failed!")

        # start with a file name dialog
        self.top.add_from_file(glade_file)
        # self.top = Glade()

        self.fam_liststore = self.top.get_object("fam_liststore")
        self.ch_liststore = self.top.get_object("ch_liststore")
        self.ch_liststore_s = self.top.get_object("ch_liststore_s")
        self.fam_view = self.top.get_object("Families_treeview")
        self.ch_view = self.top.get_object("children_treeview")
        self.ch_view_s = self.top.get_object("children_treeview_s")
        chs_style_cntx = self.ch_view.get_style_context()
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(CSS.encode('utf8'))
        chs_style_cntx.add_provider(style_provider,
                                    Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
        window = self.top.get_object("main")
        self.set_window(window, None, TITLE)
        self.setup_configs('interface.birthordertool', 750, 520)

        self.top.connect_signals({
            "on_close": self.close,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_event": self.close,
            "on_accept_clicked": self.on_accept,
            "on_easy_clicked": self.on_easy,
            "on_accept_all_clicked": self.on_accept_all,
            "on_up_btn_clicked": self.on_up,
            "on_down_btn_clicked": self.on_down
        })

        self.fam_sel = self.fam_view.get_selection()
        self.fam_sel.connect('changed', self.on_fam_row_changed)
        self.ch_s_sel = self.ch_view_s.get_selection()
        self.show()

        self.find_potentials()

        if len(self.fam_liststore) == 0:
            self.kill_buttons()
            OkDialog(_("No families need sorting"),
                     _("No children were out of birth order."),
                     parent=self.window)

    def build_menu_names(self, obj):
        return (TITLE, TITLE)

    def kill_buttons(self):
        self.top.get_object("AcceptAll").set_sensitive(False)
        self.top.get_object("AcceptAllEasy").set_sensitive(False)
        self.top.get_object("accept").set_sensitive(False)
        self.top.get_object("up_btn").set_sensitive(False)
        self.top.get_object("down_btn").set_sensitive(False)

    def on_help_clicked(self, dummy):
        """ Button: Display the relevant portion of GRAMPS manual"""
        display_url(WIKI_PAGE)

    def on_accept(self, dummy):
        """ Button: Accept the single family as shown """
        orig_ref_list = self.family.get_child_ref_list()
        child_ref_list = []
        for child_iter in self.ch_liststore_s:
            child_ref_list.append(orig_ref_list[child_iter[2]])
        self.family.set_child_ref_list(child_ref_list)
        with DbTxn(_("Edit Family"), self.db) as trans:
            self.db.commit_family(self.family, trans)
        self.fam_liststore.remove(self.fam_iter)
        if len(self.fam_liststore) == 0:
            self.kill_buttons()
            self.ch_liststore.clear()
            self.ch_liststore_s.clear()
        else:
            if not self.fam_sel.get_selected()[1]:
                self.fam_sel.select_path(Gtk.TreePath.new_first())

    def on_accept_all(self, dummy, easy=False):
        """ Button: Accept all or all the 'easy' ones, depending """
        self.progress = ProgressMeter(TITLE, '', parent=self.window)
        length = self.easy_count if easy else len(self.fam_liststore)

        self.progress.set_pass(_("Processing..."), length)
        with DbTxn(_("Edit Families"), self.db) as trans:
            for row in self.fam_liststore:
                self.progress.step()
                if easy and not row[0]:
                    continue
                self.fam_h = row[4]
                self.family = self.db.get_family_from_handle(self.fam_h)
                dummy, sorted_ch_list = self.sort_family_pr(self.fam_h)
                orig_refs = self.family.get_child_ref_list()
                sort_ref_list = list(orig_refs[ch[3]] for ch in sorted_ch_list)
                self.family.set_child_ref_list(sort_ref_list)
                self.db.commit_family(self.family, trans)
                self.fam_liststore.remove(row.iter)
        self.progress.close()
        spath = Gtk.TreePath.new_first()
        self.fam_sel.select_path(spath)
        if len(self.fam_liststore) == 0:
            self.kill_buttons()
            self.ch_liststore.clear()
            self.ch_liststore_s.clear()

    def on_easy(self, obj):
        """ Button: Accept all the 'easy' ones """
        self.on_accept_all(obj, easy=True)

    def on_fam_row_changed(self, *obj):
        """ Signal: update lower panes when the family pane row changes """
        if not obj:
            return
        self.fam_iter = obj[0].get_selected()[1]
        if not self.fam_iter:
            return
        self.fam_h = self.fam_liststore[self.fam_iter][4]
        self.family = self.db.get_family_from_handle(self.fam_h)
        ch_list, sorted_ch_list = self.sort_family_pr(self.fam_h)
        self.ch_liststore.clear()
        self.ch_liststore_s.clear()
        for indx in range(len(ch_list)):
            ch_row = (ch_list[indx][0], ch_list[indx][1])
            ch_row_s = (sorted_ch_list[indx][0], sorted_ch_list[indx][1],
                        sorted_ch_list[indx][3])
            self.ch_liststore.append(row=ch_row)
            self.ch_liststore_s.append(row=ch_row_s)
        self.ch_s_sel.select_path(Gtk.TreePath.new_first())

    def ch_sorted_index(self):
        """ get the index of current sorted view pane selected row """
        ch_path = self.ch_view_s.get_selection().get_selected_rows()[1][0]
        return int(str(ch_path))

    def on_up(self, dummy):
        """ Button: move the selected sorted view row up """
        pos = self.ch_sorted_index()
        new_order = list(range(len(self.ch_liststore_s)))
        if pos > 0:
            new_order[pos] = pos - 1
            new_order[pos - 1] = pos
            self.ch_liststore_s.reorder(new_order)

    def on_down(self, dummy):
        """ Button: move the selected sorted view row down """
        pos = self.ch_sorted_index()
        new_order = list(range(len(self.ch_liststore_s)))
        if pos >= 0 and pos < len(self.ch_liststore_s) - 1:
            new_order[pos] = pos + 1
            new_order[pos + 1] = pos
            self.ch_liststore_s.reorder(new_order)

    def find_potentials(self):
        """ look for possible out of order families """
        self.progress = ProgressMeter(TITLE,
                                      _('Looking for children birth order'),
                                      parent=self.window)
        length = self.db.get_number_of_families()

        self.progress.set_pass(_('Pass 1: Building preliminary lists'), length)
        self.easy_count = 0
        for fam_h in self.db.iter_family_handles():
            self.progress.step()
            fam = self.db.get_family_from_handle(fam_h)
            child_ref_list = fam.get_child_ref_list()
            prev_date = 0
            need_sort = False
            easy = '*'
            for child_ref in child_ref_list:
                child = self.db.get_person_from_handle(child_ref.ref)
                b_date = 0
                birth = get_birth_or_fallback(self.db, child)
                if birth:
                    b_date = birth.get_date_object().get_sort_value()
                if not b_date:
                    easy = ''
                    continue
                elif b_date >= prev_date:
                    prev_date = b_date
                    continue
                else:  # we need to put this one in list
                    need_sort = True
            if not need_sort:
                continue
            if easy:
                self.easy_count += 1
            fam_f = fam.get_father_handle()
            fam_m = fam.get_mother_handle()
            if fam_f:
                father = self.db.get_person_from_handle(fam_f)
                father_name = name_displayer.display(father)
            else:
                father_name = ''
            if fam_m:
                mother = self.db.get_person_from_handle(fam_m)
                mother_name = name_displayer.display(mother)
            else:
                mother_name = ''
            fam_data = (easy, fam.get_gramps_id(), father_name, mother_name,
                        fam_h)
            self.fam_liststore.append(row=fam_data)
        if len(self.fam_liststore) != 0:
            spath = Gtk.TreePath.new_first()
            self.fam_sel.select_path(spath)
            self.ch_s_sel.select_path(spath)
        self.progress.close()

    def sort_family_pr(self, fam_h):
        """ This prepares the family; list of children and the proposed list
            of sorted children.  It also returns an indicator of 'easy', i.e.
            if all children have valid dates.
        """
        fam = self.db.get_family_from_handle(fam_h)
        child_ref_list = fam.get_child_ref_list()
        children = []
        for index, child_ref in enumerate(child_ref_list):
            child = self.db.get_person_from_handle(child_ref.ref)
            birth = get_birth_or_fallback(self.db, child)
            if birth:
                b_date_s = birth.get_date_object().get_sort_value()
                birth_str = displayer.display(birth.get_date_object())
            else:
                b_date_s = 0
                birth_str = ""
            children.append(
                (name_displayer.display(child), birth_str, b_date_s, index))
        sorted_children = sorted(children, key=lambda child: child[2])
        return (children, sorted_children)
Exemple #43
0
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
    """ Class for Reodering Gramps ID Tool """
    xobjects = (('person', 'people'), ('family', 'families'),
                ('event', 'events'), ('place', 'places'),
                ('source', 'sources'), ('citation', 'citations'),
                ('repository', 'repositories'), ('media', 'media'), ('note',
                                                                     'notes'))

    def build_menu_names_(self, widget=None):
        """ The menu name """
        return (_('Main window'), _("Reorder Gramps IDs"))

    def __init__(self, dbstate, user, options_class, name, callback=None):
        self.uistate = user.uistate
        self.db = dbstate.db

        if self.uistate:
            tool.BatchTool.__init__(self, dbstate, user, options_class, name)
            if self.fail:
                return  # user denied to modify Gramps IDs

        ManagedWindow.__init__(self, self.uistate, [], self.__class__)
        if not self.uistate:
            UpdateCallback.__init__(self, user.callback)

        self.object_status = True
        self.change_status = False
        self.start_zero = True
        self.step_cnt, self.step_list = 0, ['1', '2', '5', '10']
        self.keep_status = True

        self.obj_values = {}  # enable access to all internal values
        self.active_entries, self.format_entries = {}, {}
        self.change_entries = {}
        self.start_entries, self.step_entries = {}, {}
        self.keep_entries = {}

        self.prim_methods, self.obj_methods = {}, {}
        for prim_obj, prim_objs in self.xobjects:
            get_handles = "get_%s_handles" % prim_obj
            get_number_obj = "get_number_of_%s" % prim_objs
            prefix_fmt = "%s_prefix" % prim_obj
            get_from_id = "get_%s_from_gramps_id" % prim_obj
            get_from_handle = "get_%s_from_handle" % prim_obj
            next_from_id = "find_next_%s_gramps_id" % prim_obj
            commit = "commit_%s" % prim_obj

            self.prim_methods[prim_obj] = (getattr(self.db, prefix_fmt),
                                           getattr(self.db, get_number_obj)(),
                                           getattr(self.db, next_from_id)())
            self.obj_methods[prim_obj] = (getattr(self.db, get_handles),
                                          getattr(self.db, commit),
                                          getattr(self.db, get_from_id),
                                          getattr(self.db, get_from_handle),
                                          getattr(self.db, next_from_id))

            object_fmt, quant_id, next_id = self.prim_methods[prim_obj]

            obj_value = ReorderEntry(object_fmt, quant_id, next_id, prim_obj)
            self.obj_values[prim_obj] = obj_value

        if self.uistate:
            self._display()
        else:
            self._execute()

    def __on_object_button_clicked(self, widget=None):
        """ compute all primary objects and toggle the 'Active' attribute """
        self.object_status = not self.object_status

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_active' % prim_obj)
            obj.set_active(self.object_status)

    def __on_object_button_toggled(self, widget):
        """ compute the primary object and toggle the 'Sensitive' attribute """
        obj_state = widget.get_active()
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]

        self.active_entries[obj_name].set_val(obj_state)

        for obj_entry in ['actual', 'quant', 'format', 'change']:
            obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
            obj.set_sensitive(obj_state)

        for obj_entry in ['start', 'step', 'keep']:
            obj = self.top.get_object('%s_change' % obj_name)
            if obj.get_active():
                obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
                obj.set_sensitive(obj_state)

    def __on_format_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Format' scheme of identifiers """
        for prim_obj, dummy in self.xobjects:
            obj_format = self.top.get_object('%s_format' % prim_obj)
            if not obj_format.get_sensitive():
                continue

            obj_fmt = self.obj_values[prim_obj].res_fmt()
            self.format_entries[prim_obj].force_value(obj_fmt)
            if self.start_zero:
                obj_id = self.obj_values[prim_obj].zero_id()
            else:
                obj_id = self.obj_values[prim_obj].last_id()
            self.start_entries[prim_obj].force_value(obj_id)

    def __on_change_button_clicked(self, widget=None):
        """ compute all primary objects and toggle the 'Change' attribute """
        self.change_status = not self.change_status

        for prim_obj, dummy in self.xobjects:
            obj_change = self.top.get_object('%s_change' % prim_obj)
            if not obj_change.get_sensitive():
                continue

            self.change_entries[prim_obj].set_val(self.change_status)
            obj_change.set_active(self.change_status)

    def __on_change_button_toggled(self, widget):
        """ compute the primary object and toggle the 'Sensitive' attribute """
        obj_state = widget.get_active()
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]

        for obj_entry in ['start', 'step', 'keep']:
            obj = self.top.get_object('%s_%s' % (obj_name, obj_entry))
            if obj_entry == 'keep':
                if (self.obj_values[obj_name].stored_prefix !=
                        self.obj_values[obj_name].object_prefix
                        and self.obj_values[obj_name].stored_suffix !=
                        self.obj_values[obj_name].object_suffix):
                    self.keep_entries[obj_name].set_val(False)
                else:
                    obj.set_active(obj_state)
                    self.keep_entries[obj_name].set_val(obj_state)
            obj.set_sensitive(obj_state)

    def __on_start_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Start' values of identifiers """
        self.start_zero = not self.start_zero

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_start' % prim_obj)
            if not obj.get_sensitive():
                continue

            if self.start_zero:
                obj_id = self.obj_values[prim_obj].zero_id()
            else:
                obj_id = self.obj_values[prim_obj].next_id()
            self.start_entries[prim_obj].force_value(obj_id)

    def __on_step_button_clicked(self, widget=None):
        """ compute all sensitive primary objects and sets the
            'Step' width of identifiers """
        self.step_cnt = self.step_cnt + 1 if self.step_cnt < 3 else 0

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_step' % prim_obj)
            if not obj.get_sensitive():
                continue

            step_val = self.step_list[self.step_cnt]
            self.step_entries[prim_obj].force_value(step_val)

    def __on_keep_button_clicked(self, widget=None):
        """ compute the primary object and toggle the 'Active' attribute """
        self.keep_status = not self.keep_status

        for prim_obj, dummy in self.xobjects:
            obj = self.top.get_object('%s_change' % prim_obj)
            if not obj.get_active():
                continue

            obj = self.top.get_object('%s_keep' % prim_obj)
            obj.set_active(self.keep_status)
            self.keep_entries[prim_obj].set_val(self.keep_status)

    def __on_format_entry_keyrelease(self, widget, event, data=None):
        """ activated on all return's of an entry """
        if event.keyval in [Gdk.KEY_Return]:
            obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
            obj_fmt = self.format_entries[obj_name].get_val()
            self.format_entries[obj_name].force_value(obj_fmt)
            self.start_entries[obj_name].update()

            obj_change = self.top.get_object('%s_change' % obj_name)
            obj_change.grab_focus()

        return False

    def __on_format_entry_focusout(self, widget, event, data=None):
        """ activated on all focus out of an entry """
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
        obj_fmt = self.format_entries[obj_name].get_val()

        self.format_entries[obj_name].set_text(obj_fmt)
        self.start_entries[obj_name].update()

        return False

    def __on_start_entry_focusout(self, widget, event, data=None):
        """ activated on all focus out of an entry """
        obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0]
        self.start_entries[obj_name].update()

        return False

    def __on_ok_button_clicked(self, widget=None):
        """ execute the reodering and close """
        self._execute()
        self._update()

        self.close()

    def __on_cancel_button_clicked(self, widget=None):
        """ cancel the reodering and close """
        self.close()

    def __on_help_button_clicked(self, widget=None):
        """ display the relevant portion of Gramps manual """
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def _display(self):
        """ organize Glade 'Reorder IDs' window """

        # get the main window from glade
        self.top = Glade(toplevel="reorder-ids")
        window = self.top.toplevel

        # set gramps style title for the window
        self.set_window(window, self.top.get_object("title"),
                        _("Reorder Gramps IDs"))

        # connect signals
        self.top.connect_signals({
            "on_object_button_clicked":
            self.__on_object_button_clicked,
            "on_object_button_toggled":
            self.__on_object_button_toggled,
            "on_format_button_clicked":
            self.__on_format_button_clicked,
            "on_start_button_clicked":
            self.__on_start_button_clicked,
            "on_step_button_clicked":
            self.__on_step_button_clicked,
            "on_keep_button_clicked":
            self.__on_keep_button_clicked,
            "on_change_button_clicked":
            self.__on_change_button_clicked,
            "on_change_button_toggled":
            self.__on_change_button_toggled,
            "on_format_entry_keyrelease":
            self.__on_format_entry_keyrelease,
            "on_format_entry_focusout":
            self.__on_format_entry_focusout,
            "on_start_entry_focusout":
            self.__on_start_entry_focusout,
            "on_help_button_clicked":
            self.__on_help_button_clicked,
            "on_cancel_button_clicked":
            self.__on_cancel_button_clicked,
            "on_ok_button_clicked":
            self.__on_ok_button_clicked
        })

        # Calculate all entries and update Glade window
        for prim_obj, dummy in self.xobjects:
            # populate Object, Actual & Quantity fields with values
            obj_active = self.top.get_object('%s_active' % prim_obj)
            self.active_entries[prim_obj] = MonitoredCheckbox(
                obj_active, obj_active, self.obj_values[prim_obj].set_active,
                self.obj_values[prim_obj].get_active)
            obj_actual = self.top.get_object('%s_actual' % prim_obj)
            obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id())
            obj_quant = self.top.get_object('%s_quant' % prim_obj)
            obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id))

            # connect/populate Format, Start, Step, Keep & Change fields
            #  with GTK/values
            obj_format = self.top.get_object('%s_format' % prim_obj)
            self.format_entries[prim_obj] = MonitoredEntry(
                obj_format, self.obj_values[prim_obj].set_fmt,
                self.obj_values[prim_obj].get_fmt)
            obj_change = self.top.get_object('%s_change' % prim_obj)
            self.change_entries[prim_obj] = MonitoredCheckbox(
                obj_change, obj_change, self.obj_values[prim_obj].set_change,
                self.obj_values[prim_obj].get_change)
            obj_start = self.top.get_object('%s_start' % prim_obj)
            self.start_entries[prim_obj] = MonitoredEntry(
                obj_start, self.obj_values[prim_obj].set_id,
                self.obj_values[prim_obj].get_id)
            obj_step = self.top.get_object('%s_step' % prim_obj)
            self.step_entries[prim_obj] = MonitoredEntry(
                obj_step,
                self.obj_values[prim_obj].set_step,
                self.obj_values[prim_obj].get_step,
                changed=self.obj_values[prim_obj].change_step)
            obj_keep = self.top.get_object('%s_keep' % prim_obj)
            self.keep_entries[prim_obj] = MonitoredCheckbox(
                obj_keep,
                obj_keep,
                self.obj_values[prim_obj].set_keep,
                self.obj_values[prim_obj].get_keep,
                readonly=True)

        # fetch the popup menu
        self.menu = self.top.get_object("popup_menu")

        # ok, let's see what we've done
        self.window.resize(700, 410)
        self.show()

    def _update(self):
        """ store changed objects formats in DB """

        update = False
        for prim_obj, dummy in self.xobjects:
            obj_value = self.obj_values[prim_obj]
            if obj_value.object_fmt != obj_value.stored_fmt:
                constant = 'preferences.%sprefix' % PREFIXES[prim_obj]
                config.set(constant, obj_value.object_fmt)
                update = True

        if update:
            config.save()
            self.db.set_prefixes(config.get('preferences.iprefix'),
                                 config.get('preferences.oprefix'),
                                 config.get('preferences.fprefix'),
                                 config.get('preferences.sprefix'),
                                 config.get('preferences.cprefix'),
                                 config.get('preferences.pprefix'),
                                 config.get('preferences.eprefix'),
                                 config.get('preferences.rprefix'),
                                 config.get('preferences.nprefix'))

    def _execute(self):
        """ execute all primary objects and reorder if neccessary """

        # Update progress calculation
        if self.uistate:
            self.progress = ProgressMeter(_('Reorder Gramps IDs'), '')
        else:
            total_objs = 0
            for prim_obj, dummy in self.xobjects:
                if self.obj_values[prim_obj].active_obj:
                    total_objs += self.obj_values[prim_obj].quant_id
            self.set_total(total_objs)

        # Update database
        self.db.disable_signals()
        for prim_obj, prim_objs in self.xobjects:
            with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.db,
                       batch=True) as self.trans:
                if self.obj_values[prim_obj].active_obj:
                    if self.uistate:
                        self.progress.set_pass(
                            _('Reorder %s IDs ...') % _(prim_objs.title()),
                            self.obj_values[prim_obj].quant_id)
                    # reset the db next_id index to zero so we restart new IDs
                    # at lowest possible position
                    setattr(self.db, DB_INDXES[prim_obj] + 'map_index', 0)
                    # Process reordering
                    self._reorder(prim_obj)

        self.db.enable_signals()
        self.db.request_rebuild()

        # Update progress calculation
        if self.uistate:
            self.progress.close()
        else:
            print('\nDone.')

    # finds integer portion in a GrampsID
    _findint = re.compile(r'^[^\d]*(\d+)[^\d]*$')
    # finds prefix, number, suffix of a Gramps ID ignoring a leading or
    # trailing space.  The number must be at least three digits.
    _prob_id = re.compile(r'^ *([^\d]*)(\d{3,9})([^\d]*) *$')

    def _reorder(self, prim_obj):
        """ reorders all selected objects with a (new) style, start & step """

        dup_ids = []  # list of duplicate identifiers
        new_ids = {}  # list of new identifiers

        get_handles, commit, get_from_id, get_from_handle, next_from_id = \
            self.obj_methods[prim_obj]

        prefix_fmt = self.obj_values[prim_obj].get_fmt()
        prefix = self.obj_values[prim_obj].object_prefix
        suffix = self.obj_values[prim_obj].object_suffix
        old_pref = self.obj_values[prim_obj].stored_prefix
        old_suff = self.obj_values[prim_obj].stored_suffix
        new_id = self.obj_values[prim_obj].get_id()
        keep_fmt = self.obj_values[prim_obj].get_keep()
        change = self.obj_values[prim_obj].get_change()
        index_max = int("9" * self.obj_values[prim_obj].width_fmt)
        do_same = False
        # Process in handle order, which is in order handles were created.
        # This makes renumberd IDs more consistant.
        handles = get_handles()
        handles.sort()

        for handle in handles:
            # Update progress
            if self.uistate:
                self.progress.step()
            else:
                self.update()

            # extract basic data out of the database
            obj = get_from_handle(handle)

            act_id = obj.get_gramps_id()
            # here we see if the ID looks like a new or previous or default
            # Gramps ID.
            # If not we ask user if he really wants to replace it.
            # This should allow user to protect a GetGov ID or similar
            match = self._prob_id.match(act_id)
            if not (match and
                    (prefix == match.groups()[0] and suffix
                     == match.groups()[2] or old_pref == match.groups()[0] and
                     old_suff == match.groups()[2] or len(match.groups()[0])
                     == 1 and len(match.groups()[2]) == 0)) and not do_same:
                xml = Glade(toplevel='dialog')

                top = xml.toplevel
                # self.top.set_icon(ICON)
                top.set_title("%s - Gramps" % _("Reorder Gramps IDs"))
                apply_to_rest = xml.get_object('apply_to_rest')

                label1 = xml.get_object('toplabel')
                label1.set_text('<span weight="bold" size="larger">%s</span>' %
                                _("Reorder Gramps IDs"))
                label1.set_use_markup(True)

                label2 = xml.get_object('mainlabel')
                label2.set_text(_("Do you want to replace %s?" % act_id))
                top.set_transient_for(self.progress._ProgressMeter__dialog)
                self.progress._ProgressMeter__dialog.set_modal(False)
                top.show()
                response = top.run()
                do_same = apply_to_rest.get_active()
                top.destroy()
                self.progress._ProgressMeter__dialog.set_modal(True)
                if response != Gtk.ResponseType.YES:
                    continue

            elif not match and do_same and response != Gtk.ResponseType.YES:
                continue

            if change:
                # update the defined ID numbers into objects under
                # consideration of keeping ID if format not matches prefix
                # (implication logical boolean operator below)
                if act_id.startswith(prefix) and act_id.endswith(suffix) or \
                        not keep_fmt:
                    obj.set_gramps_id(new_id)
                    commit(obj, self.trans)
                    new_id = self.obj_values[prim_obj].succ_id()
            else:
                # attempt to extract integer - if we can't, treat it as a
                # duplicate
                try:
                    match = self._findint.match(act_id)
                    if match:
                        # get the integer, build the new handle. Make sure it
                        # hasn't already been chosen. If it has, put this
                        # in the duplicate handle list

                        index = int(match.groups()[0])
                        if index > index_max:
                            new_id = next_from_id()
                        else:
                            new_id = prefix_fmt % index

                        if new_id == act_id:
                            if new_id in new_ids:
                                dup_ids.append(obj.get_handle())
                            else:
                                new_ids[new_id] = act_id
                        elif get_from_id(new_id) is not None:
                            dup_ids.append(obj.get_handle())
                        else:
                            obj.set_gramps_id(new_id)
                            commit(obj, self.trans)
                            new_ids[new_id] = act_id
                    else:
                        dup_ids.append(handle)
                except:
                    dup_ids.append(handle)

        # go through the duplicates, looking for the first available
        # handle that matches the new scheme.
        if dup_ids:
            if self.uistate:
                self.progress.set_pass(_('Finding and assigning unused IDs.'),
                                       len(dup_ids))
            for handle in dup_ids:
                obj = get_from_handle(handle)
                obj.set_gramps_id(next_from_id())
                commit(obj, self.trans)
Exemple #44
0
class FindLoop(ManagedWindow) :

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        self.title = _('Find database loop')
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.uistate = uistate
        self.db = dbstate.db

        topDialog = Glade()

        topDialog.connect_signals({
            "destroy_passed_object" : self.close,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_event"       : self.close,
        })

        window = topDialog.toplevel
        title = topDialog.get_object("title")
        self.set_window(window, title, self.title)

        # start the progress indicator
        self.progress = ProgressMeter(self.title,_('Starting'),
                                      parent=self.window)
        self.progress.set_pass(_('Looking for possible loop for each person'),
                               self.db.get_number_of_people())

        self.model = Gtk.ListStore(
            GObject.TYPE_STRING,    # 0==father id
            GObject.TYPE_STRING,    # 1==father
            GObject.TYPE_STRING,    # 2==son id
            GObject.TYPE_STRING,    # 3==son
            GObject.TYPE_STRING)    # 4==family gid

        self.treeView = topDialog.get_object("treeview")
        self.treeView.set_model(self.model)
        col1 = Gtk.TreeViewColumn(_('Gramps ID'),     Gtk.CellRendererText(), text=0)
        col2 = Gtk.TreeViewColumn(_('Ancestor'),   Gtk.CellRendererText(), text=1)
        col3 = Gtk.TreeViewColumn(_('Gramps ID'),     Gtk.CellRendererText(), text=2)
        col4 = Gtk.TreeViewColumn(_('Descendant'),     Gtk.CellRendererText(), text=3)
        col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4)
        col1.set_resizable(True)
        col2.set_resizable(True)
        col3.set_resizable(True)
        col4.set_resizable(True)
        col5.set_resizable(True)
        col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col1.set_sort_column_id(0)
        col2.set_sort_column_id(1)
        col3.set_sort_column_id(2)
        col4.set_sort_column_id(3)
        col5.set_sort_column_id(4)
        self.treeView.append_column(col1)
        self.treeView.append_column(col2)
        self.treeView.append_column(col3)
        self.treeView.append_column(col4)
        self.treeView.append_column(col5)
        self.treeSelection = self.treeView.get_selection()
        self.treeView.connect('row-activated', self.rowactivated)

        people = self.db.get_person_handles()
        count = 0
        for person_handle in people:
            person = self.db.get_person_from_handle(person_handle)
            count += 1
            self.current = person
            self.parent = None
            self.descendants(person_handle, set())
            self.progress.set_header("%d/%d" % (count, len(people)))
            self.progress.step()

        # close the progress bar
        self.progress.close()

        self.show()

    def descendants(self, person_handle, new_list):
        person = self.db.get_person_from_handle(person_handle)
        pset = set()
        for item in new_list:
            pset.add(item)
        if person.handle in pset:
            # We found one loop
            father_id = self.current.get_gramps_id()
            father = _nd.display(self.current)
            son_id = self.parent.get_gramps_id()
            son = _nd.display(self.parent)
            value = (father_id, father, son_id, son, self.curr_fam)
            found = False
            for pth in range(len(self.model)):
                path = Gtk.TreePath(pth)
                treeiter = self.model.get_iter(path)
                find = (self.model.get_value(treeiter, 0),
                        self.model.get_value(treeiter, 1),
                        self.model.get_value(treeiter, 2),
                        self.model.get_value(treeiter, 3),
                        self.model.get_value(treeiter, 4))
                if find == value:
                    found = True
            if not found:
                self.model.append(value)
            return
        pset.add(person.handle)
        for family_handle in person.get_family_handle_list():
            family = self.db.get_family_from_handle(family_handle)
            self.curr_fam = family.get_gramps_id()
            if not family:
                # can happen with LivingProxyDb(PrivateProxyDb(db))
                continue
            for child_ref in family.get_child_ref_list():
                child_handle = child_ref.ref
                self.parent = person
                self.descendants(child_handle, pset)

    def rowactivated(self, treeView, path, column) :
        # first we need to check that the row corresponds to a person
        iter = self.model.get_iter(path)
        From_id = self.model.get_value(iter, 0)
        To_id = self.model.get_value(iter, 2)
        Fam_id = self.model.get_value(iter, 4)
        fam = self.dbstate.db.get_family_from_gramps_id(Fam_id)
        if fam:
            try:
                EditFamily(self.dbstate, self.uistate, [], fam)
            except WindowActiveError:
                pass
            return True
        return False

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def close(self, *obj):
        ManagedWindow.close(self,*obj)
Exemple #45
0
class ExtractCity(tool.BatchTool, ManagedWindow):
    """
    Extracts city, state, and zip code information from an place description
    if the title is empty and the description falls into the category of:

       New York, NY 10000

    Sorry for those not in the US or Canada. I doubt this will work for any
    other locales.
    Works for Sweden if the decriptions is like
        Stockholm (A)
    where the letter A is the abbreviation letter for laen.
    Works for France if the description is like
        Paris, IDF 75000, FRA
    or  Paris, ILE DE FRANCE 75000, FRA
    """

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _('Extract Place data')

        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)

        if not self.fail:
            uistate.set_busy_cursor(True)
            self.run(dbstate.db)
            uistate.set_busy_cursor(False)

    def run(self, db):
        """
        Performs the actual extraction of information
        """

        self.progress = ProgressMeter(_('Checking Place Titles'), '')
        self.progress.set_pass(_('Looking for place fields'),
                               self.db.get_number_of_places())

        self.name_list = []
        self.place_import = PlaceImport(db)

        for place in db.iter_places():
            descr = place_displayer.display(db, place)
            self.progress.step()

            loc = get_main_location(db, place)
            location = ((loc.get(PlaceType.STREET, '')),
                        (loc.get(PlaceType.LOCALITY, '')),
                        (loc.get(PlaceType.PARISH, '')),
                        (loc.get(PlaceType.CITY, '')),
                        (loc.get(PlaceType.COUNTY, '')),
                        (loc.get(PlaceType.STATE, '')),
                        (loc.get(PlaceType.COUNTRY, '')))
            self.place_import.store_location(location, place.handle)

            if len(place.get_placeref_list()) == 0:

                match = CITY_STATE_ZIP.match(descr.strip())
                if match:
                    data = match.groups()
                    city = data[0]
                    state = data[2]
                    postal = data[5]

                    val = " ".join(state.strip().split()).upper()
                    if state:
                        new_state = STATE_MAP.get(val.upper())
                        if new_state:
                            self.name_list.append(
                                (place.handle, (city, new_state[0], postal,
                                          COUNTRY[new_state[1]])))
                    continue

                # Check if there is a left parant. in the string, might be Swedish laen.
                match = CITY_LAEN.match(descr.strip().replace(","," "))
                if match:
                    data = match.groups()
                    city = data[0]
                    state = '(' + data[1] + ')'
                    postal = None
                    val = " ".join(state.strip().split()).upper()
                    if state:
                        new_state = STATE_MAP.get(val.upper())
                        if new_state:
                            self.name_list.append(
                                (place.handle, (city, new_state[0], postal,
                                          COUNTRY[new_state[1]])))
                    continue
                match = CITY_STATE.match(descr.strip())
                if match:
                    data = match.groups()
                    city = data[0]
                    state = data[1]
                    postal = None
                    if state:
                        m0 = STATE_ZIP.match(state)
                        if m0:
                            (state, postal) = m0.groups()

                    val = " ".join(state.strip().split()).upper()
                    if state:
                        new_state = STATE_MAP.get(val.upper())
                        if new_state:
                            self.name_list.append(
                                (place.handle, (city, new_state[0], postal,
                                          COUNTRY[new_state[1]])))
                    continue

                val = " ".join(descr.strip().split()).upper()
                new_state = STATE_MAP.get(val)
                if new_state:
                    self.name_list.append(
                        (place.handle, (None, new_state[0], None,
                                  COUNTRY[new_state[1]])))
        self.progress.close()

        if self.name_list:
            self.display()
        else:
            self.close()
            from gramps.gui.dialog import OkDialog
            OkDialog(_('No modifications made'),
                     _("No place information could be extracted."))

    def display(self):

        self.top = Glade("changenames.glade")
        window = self.top.toplevel
        self.top.connect_signals({
            "destroy_passed_object" : self.close,
            "on_ok_clicked" : self.on_ok_clicked,
            "on_help_clicked" : self.on_help_clicked,
            "on_delete_event"   : self.close,
            })

        self.list = self.top.get_object("list")
        self.set_window(window, self.top.get_object('title'), self.label)
        lbl = self.top.get_object('info')
        lbl.set_line_wrap(True)
        lbl.set_text(
            _('Below is a list of Places with the possible data that can '
              'be extracted from the place title. Select the places you '
              'wish Gramps to convert.'))

        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING)

        r = Gtk.CellRendererToggle()
        r.connect('toggled', self.toggled)
        c = Gtk.TreeViewColumn(_('Select'), r, active=0)
        self.list.append_column(c)

        for (title, col) in COLS:
            render = Gtk.CellRendererText()
            if col > 1:
                render.set_property('editable', True)
                render.connect('edited', self.__change_name, col)

            self.list.append_column(
                Gtk.TreeViewColumn(title, render, text=col))
        self.list.set_model(self.model)

        self.iter_list = []
        self.progress.set_pass(_('Building display'), len(self.name_list))
        for (id, data) in self.name_list:

            place = self.db.get_place_from_handle(id)
            descr = place_displayer.display(self.db, place)

            handle = self.model.append()
            self.model.set_value(handle, 0, True)
            self.model.set_value(handle, 1, descr)
            if data[0]:
                self.model.set_value(handle, 2, data[0])
            if data[1]:
                self.model.set_value(handle, 3, data[1])
            if data[2]:
                self.model.set_value(handle, 4, data[2])
            if data[3]:
                self.model.set_value(handle, 5, data[3])
            self.model.set_value(handle, 6, id)
            self.iter_list.append(handle)
            self.progress.step()
        self.progress.close()

        self.show()

    def __change_name(self, text, path, new_text, col):
        self.model[path][col] = new_text
        return

    def toggled(self, cell, path_string):
        path = tuple(map(int, path_string.split(':')))
        row = self.model[path]
        row[0] = not row[0]

    def build_menu_names(self, obj):
        return (self.label, None)

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help()

    def on_ok_clicked(self, obj):
        with DbTxn(_("Extract Place data"), self.db, batch=True) as self.trans:
            self.db.disable_signals()
            changelist = [node for node in self.iter_list
                          if self.model.get_value(node, 0)]

            for change in changelist:
                row = self.model[change]
                place = self.db.get_place_from_handle(row[6])
                location = ('', '', '', row[2], '', row[3], row[5])
                self.place_import.store_location(location, place.handle)
                if row[2]:
                    place.set_name(PlaceName(value=row[2]))
                place.set_type(PlaceType.CITY)
                if row[4]:
                    place.set_code(row[4])
                self.db.commit_place(place, self.trans)

            self.place_import.generate_hierarchy(self.trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        self.close()
class ChangeGivenNames(tool.BatchTool, ManagedWindow):

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _('Capitalization changes')
        self.dbstate = dbstate
        self.uistate = uistate
        self.cb = callback

        ManagedWindow.__init__(self,uistate,[],self.__class__)
        self.set_window(Gtk.Window(),Gtk.Label(),'')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        given_name_dict = self.get_given_name_dict()

        self.progress = ProgressMeter(_('Checking Given Names'),'',
                                      parent=uistate.window)
        self.progress.set_pass(_('Searching given names'),
                               len(given_name_dict.keys()))
        self.name_list = []

        for name in given_name_dict.keys():
            if name != capitalize(name):
                self.name_list.append((name, given_name_dict[name]))

            if uistate:
                self.progress.step()

        if self.name_list:
            self.display()
        else:
            self.progress.close()
            self.close()
            OkDialog(_('No modifications made'),
                     _("No capitalization changes were detected."),
                     parent=uistate.window)

    def get_given_name_dict(self):
        givennames = {}
        self.name_map = {}
        for person in self.db.iter_people():
            allnames = [person.get_primary_name()] + person.get_alternate_names()
            allnames = set(name.get_first_name().strip() for name in allnames)
            for givenname in allnames:
                givennames[givenname] = givennames.get(givenname, 0) + 1
                self.name_map[givenname] = self.name_map.get(givenname, set([]))
                self.name_map[givenname].add(person.handle)
        return givennames

    def display(self):

        if lin():
            import locale, os
            locale.setlocale(locale.LC_ALL, '')
            # This is needed to make gtk.Builder work by specifying the
            # translations directory
            base = os.path.dirname(__file__)
            locale.bindtextdomain("addon", base + "/locale")

            self.glade = Gtk.Builder()
            self.glade.set_translation_domain("addon")

            path = base + "/changenames.glade"
            self.glade.add_from_file(path)

            #from gi.repository import GObject
            GObject.GObject.__init__(self.glade)

            self.top = self.glade.get_object('changenames')

            self.glade.connect_signals({
                "destroy_passed_object" : self.close,
                "on_ok_clicked" : self.on_ok_clicked,
                "on_help_clicked" : self.on_help_clicked,
                "on_edit_clicked" : self.on_edit_clicked,
                "on_delete_event"   : self.close,
                })

            self.list = self.glade.get_object("list")
            self.set_window(self.top, self.glade.get_object('title'), self.label)

        else:
            self.top = Glade("changenames.glade")

            window = self.top.toplevel
            self.top.connect_signals({
                "destroy_passed_object" : self.close,
                "on_ok_clicked" : self.on_ok_clicked,
                "on_help_clicked" : self.on_help_clicked,
                "on_edit_clicked" : self.on_edit_clicked,
                "on_delete_event"   : self.close,
                })

            self.list = self.top.get_object("list")
            self.set_window(window,self.top.get_object('title'),self.label)

        # selected, original name, changed, count
        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_INT)
        self.handles = {}

        r = Gtk.CellRendererToggle()
        r.connect('toggled',self.toggled)
        c = Gtk.TreeViewColumn(_('Select'),r,active=0)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Original Name'),
                               Gtk.CellRendererText(),text=1)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Capitalization Change'),
                               Gtk.CellRendererText(),text=2)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Affected Names'),
                               Gtk.CellRendererText(),text=3)
        self.list.append_column(c)

        self.list.set_model(self.model)

        self.iter_list = []
        self.progress.set_pass(_('Building display'),len(self.name_list))
        for name, count in self.name_list:
            handle = self.model.append()
            self.model.set_value(handle,0, False)
            self.model.set_value(handle,1, name)
            namecap = capitalize(name)
            self.model.set_value(handle,2, namecap)
            self.model.set_value(handle,3, count)
            self.iter_list.append(handle)
            self.progress.step()
        self.progress.close()

        self.show()

    def toggled(self,cell,path_string):
        path = tuple(map(int, path_string.split(':')))
        row = self.model[path]
        row[0] = not row[0]

    def build_menu_names(self, obj):
        return (self.label,None)

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC)

    def on_edit_clicked(self, button):
        """Edit the selected person"""
        from gramps.gui.editors import EditPerson
        selection = self.list.get_selection()
        store, paths = selection.get_selected_rows()
        tpath = paths[0] if len(paths) > 0 else None
        node = store.get_iter(tpath) if tpath else None
        if node:
            name = store.get_value(node, 1)
            for handle in self.name_map[name]:
                person = self.dbstate.db.get_person_from_handle(handle)
                EditPerson(self.dbstate, self.uistate, [], person)

    def on_ok_clicked(self, obj):
        with DbTxn(_("Capitalization changes"), self.db, batch=True
                   ) as self.trans:
            self.db.disable_signals()
            changelist = set(self.model.get_value(node,1)
                             for node in self.iter_list
                                if self.model.get_value(node,0))

            for handle in self.db.get_person_handles(False):
                person = self.db.get_person_from_handle(handle)
                change = False
                for name in [person.get_primary_name()] + person.get_alternate_names():
                    if name.first_name in changelist:
                        change = True
                        fname = capitalize(name.first_name)
                        name.set_first_name(fname)
                if change:
                    self.db.commit_person(person, self.trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        self.close()
        self.cb()
Exemple #47
0
    def _createmap(self,place_x):
        """
        Create all markers for each people's event in the database which has
        a lat/lon.
        """
        dbstate = self.dbstate
        self.cal = config.get('preferences.calendar-format-report')
        self.place_list = []
        self.places_found = []
        self.place_without_coordinates = []
        self.minlat = 0.0
        self.maxlat = 0.0
        self.minlon = 0.0
        self.maxlon = 0.0
        self.minyear = 9999
        self.maxyear = 0
        self.without = 0
        latitude = ""
        longitude = ""
        self.nbmarkers = 0
        self.nbplaces = 0
        self.message_layer.clear_messages()
        self.message_layer.clear_font_attributes()
        self.no_show_places_in_status_bar = False
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 1'23"
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization
        # base "villes de france" : 38101 places :
        # gramps 3.4 python 2.7 ( draw_markers are estimated when we move the map)
        # 38101 places : createmap : 04'32"; create_markers : 0'04"; draw markers : N/A :: 0'03"
        # 65598 places : createmap : 10'03"; create_markers : 0'07"; draw markers : N/A :: 0'05"
        # gramps 3.5 python 2.7 new marker layer
        # 38101 places : createmap : 03'09"; create_markers : 0'01"; draw markers : 0'04"
        # 65598 places : createmap : 08'48"; create_markers : 0'01"; draw markers : 0'07"
        _LOG.debug("%s" % time.strftime("start createmap : "
                   "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.show_all:
            self.show_all = False
            try:
                places_handle = dbstate.db.get_place_handles()
            except:
                return
            progress = ProgressMeter(self.window_name, can_cancel=False,
                                     parent=self.uistate.window)
            length = len(places_handle)
            progress.set_pass(_('Selecting all places'), length)
            for place_hdl in places_handle:
                place = dbstate.db.get_place_from_handle(place_hdl)
                self._create_one_place(place)
                progress.step()
            progress.close()
        elif self.generic_filter:
            place_list = self.generic_filter.apply(dbstate.db)
            progress = ProgressMeter(self.window_name, can_cancel=False,
                                     parent=self.uistate.window)
            length = len(place_list)
            progress.set_pass(_('Selecting all places'), length)
            for place_handle in place_list:
                place = dbstate.db.get_place_from_handle(place_handle)
                self._create_one_place(place)
                progress.step()
            progress.close()
        elif place_x:
                place = dbstate.db.get_place_from_handle(place_x)
                self._create_one_place(place)
                if ( place.get_latitude() != "" and place.get_longitude() != "" ):
                    self.osm.set_center_and_zoom(float(place.get_latitude()),
                                                 float(place.get_longitude()),
                                                 int(config.get("geography.zoom")))
        _LOG.debug(" stop createmap.")
        _LOG.debug("%s" % time.strftime("begin sort : "
                   "%a %d %b %Y %H:%M:%S", time.gmtime()))
        self.sort = sorted(self.place_list,
                           key=operator.itemgetter(0)
                          )
        _LOG.debug("%s" % time.strftime("  end sort : "
                   "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.nbmarkers > 500 : # performance issue. Is it the good value ?
            self.message_layer.add_message(
                 _("The place name in the status bar is disabled."))
            self.no_show_places_in_status_bar = True
        if self.nbplaces >= self._config.get("geography.max_places") :
            self.message_layer.set_font_attributes(None,None,"red")
            self.message_layer.add_message(
                 _("The maximum number of places is reached (%d)." %
                   self._config.get("geography.max_places")))
            self.message_layer.add_message(
                 _("Some information are missing."))
            self.message_layer.add_message(
                 _("Please, use filtering to reduce this number."))
            self.message_layer.add_message(
                 _("You can modify this value in the geography option."))
            self.message_layer.add_message(
                 _("In this case, it may take time to show all markers."))

        self._create_markers()
Exemple #48
0
    def applyTagClicked(self, button) :
        progress    = None
        rows        = self.treeSelection.count_selected_rows()
        tag_name    = str(self.tagcombo.get_active_text())

        # start the db transaction
        with DbTxn("Tag not related", self.db) as transaction:

            tag = self.db.get_tag_from_name(tag_name)
            if not tag:
                # create the tag if it doesn't already exist
                tag = Tag()
                tag.set_name(tag_name)
                tag.set_priority(self.db.get_number_of_tags())
                tag_handle = self.db.add_tag(tag, transaction)
            else:
                tag_handle = tag.get_handle()

            # if more than 1 person is selected, use a progress indicator
            if rows > 1:
                progress = ProgressMeter(self.title,_('Starting'),
                                         parent=self.window)
                progress.set_pass(
                    # translators: leave all/any {...} untranslated
                    #TRANS: no singular form needed, as rows is always > 1
                    ngettext("Setting tag for {number_of} person",
                             "Setting tag for {number_of} people",
                             rows).format(number_of=rows),
                    rows)


            # iterate through all of the selected rows
            (model, paths) = self.treeSelection.get_selected_rows()

            for path in paths:
                if progress:
                    progress.step()

                # for the current row, get the GID and the person from the database
                iter        = self.model.get_iter(path)
                personGid   = self.model.get_value(iter, 1)
                person      = self.db.get_person_from_gramps_id(personGid)

                # add the tag to the person
                person.add_tag(tag_handle)

                # save this change
                self.db.commit_person(person, transaction)


        # refresh the tags column
        self.treeView.set_model(None)
        for path in paths:
            iter        = self.model.get_iter(path)
            personGid   = self.model.get_value(iter, 1)
            person      = self.db.get_person_from_gramps_id(personGid)
            self.model.set_value(iter, 3, self.get_tag_list(person))
        self.treeView.set_model(self.model)
        self.treeView.expand_all()

        if progress:
            progress.close()
Exemple #49
0
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate

        tool.Tool.__init__(self, dbstate, options_class, name)

        self.db = dbstate.db
        progress = ProgressMeter(_('Thumbnail Generator'), can_cancel=True)

        length = self.db.get_number_of_media_objects()
        progress.set_pass(_('Generating media thumbnails'),
                               length)
        for media in dbstate.db.iter_media_objects():
            full_path = media_path_full(dbstate.db, media.get_path())
            mime_type = media.get_mime_type()
            generate_thumbnail(full_path, mime_type)
            progress.step()
            if progress.get_cancelled():
                break

        length = self.db.get_number_of_people()
        progress.set_pass(_('Generating thumbnails for person references'),
                               length)
        for person in dbstate.db.iter_people():
            self.generate_thumbnails(person)
            progress.step()
            if progress.get_cancelled():
                break

        length = self.db.get_number_of_families()
        progress.set_pass(_('Generating thumbnails for family references'),
                               length)
        for family in dbstate.db.iter_families():
            self.generate_thumbnails(family)
            progress.step()
            if progress.get_cancelled():
                break

        length = self.db.get_number_of_events()
        progress.set_pass(_('Generating thumbnails for event references'),
                               length)
        for event in dbstate.db.iter_events():
            self.generate_thumbnails(event)
            progress.step()
            if progress.get_cancelled():
                break

        length = self.db.get_number_of_places()
        progress.set_pass(_('Generating thumbnails for place references'),
                               length)
        for place in dbstate.db.iter_places():
            self.generate_thumbnails(place)
            progress.step()
            if progress.get_cancelled():
                break

        length = self.db.get_number_of_sources()
        progress.set_pass(_('Generating thumbnails for source references'),
                               length)
        for source in dbstate.db.iter_sources():
            self.generate_thumbnails(source)
            progress.step()
            if progress.get_cancelled():
                break

        progress.close()
Exemple #50
0
class NotRelated(tool.ActivePersonTool, ManagedWindow) :

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        tool.ActivePersonTool.__init__(self, dbstate, uistate, options_class,
                                       name)

        if self.fail:   # bug #2709 -- fail if we have no active person
            return

        person_handle = uistate.get_active('Person')
        person = dbstate.db.get_person_from_handle(person_handle)
        self.name = person.get_primary_name().get_regular_name()
        self.title = _('Not related to "%s"') % self.name
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.uistate = uistate
        self.db = dbstate.db

        topDialog = Glade()

        topDialog.connect_signals({
            "destroy_passed_object" : self.close,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_event"       : self.close,
        })

        window = topDialog.toplevel
        title = topDialog.get_object("title")
        self.set_window(window, title, self.title)

        self.tagcombo = topDialog.get_object("tagcombo")
        tagmodel = Gtk.ListStore(str)
        self.tagcombo.set_model(tagmodel)
        self.tagcombo.set_entry_text_column(0)
        tagmodel.append((_('ToDo'),))
        tagmodel.append((_('NotRelated'),))
        self.tagcombo.set_sensitive(False)

        self.tagapply = topDialog.get_object("tagapply")
        self.tagapply.set_sensitive(False)
        self.tagapply.connect('clicked', self.applyTagClicked)

        # start the progress indicator
        self.progress = ProgressMeter(self.title,_('Starting'),
                                      parent=self.window)

        # setup the columns
        self.model = Gtk.TreeStore(
            GObject.TYPE_STRING,    # 0==name
            GObject.TYPE_STRING,    # 1==person gid
            GObject.TYPE_STRING,    # 2==parents
            GObject.TYPE_STRING,    # 3==tags
            GObject.TYPE_STRING)    # 4==family gid (not shown to user)

        # note -- don't assign the model to the tree until it has been populated,
        # otherwise the screen updates are terribly slow while names are appended
        self.treeView = topDialog.get_object("treeview")
        col1 = Gtk.TreeViewColumn(_('Name'),    Gtk.CellRendererText(), text=0)
        col2 = Gtk.TreeViewColumn(_('ID'),      Gtk.CellRendererText(), text=1)
        col3 = Gtk.TreeViewColumn(_('Parents'), Gtk.CellRendererText(), text=2)
        col4 = Gtk.TreeViewColumn(_('Tags'),    Gtk.CellRendererText(), text=3)
        col1.set_resizable(True)
        col2.set_resizable(True)
        col3.set_resizable(True)
        col4.set_resizable(True)
        col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        col1.set_sort_column_id(0)
#        col2.set_sort_column_id(1)
#        col3.set_sort_column_id(2)
        col4.set_sort_column_id(3)
        self.treeView.append_column(col1)
        self.treeView.append_column(col2)
        self.treeView.append_column(col3)
        self.treeView.append_column(col4)
        self.treeSelection = self.treeView.get_selection()
        self.treeSelection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.treeSelection.set_select_function(self.selectIsAllowed, None)
        self.treeSelection.connect('changed', self.rowSelectionChanged)
        self.treeView.connect('row-activated', self.rowActivated)

        # initialize a few variables we're going to need
        self.numberOfPeopleInDatabase    = self.db.get_number_of_people()
        self.numberOfRelatedPeople       = 0
        self.numberOfUnrelatedPeople     = 0

        # create the sets used to track related and unrelated people
        self.handlesOfPeopleToBeProcessed       = set()
        self.handlesOfPeopleAlreadyProcessed    = set()
        self.handlesOfPeopleNotRelated          = set()

        # build a set of all people related to the selected person
        self.handlesOfPeopleToBeProcessed.add(person.get_handle())
        self.findRelatedPeople()

        # now that we have our list of related people, find everyone
        # in the database who isn't on our list
        self.findUnrelatedPeople()

        # populate the treeview model with the names of unrelated people
        if self.numberOfUnrelatedPeople == 0:
            # feature request 2356: avoid genitive form
            title.set_text(_('Everyone in the database is related to %s') % self.name)
        else:
            self.populateModel()
            self.model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
            self.treeView.set_model(self.model)
#            self.treeView.set_row_separator_func(self.iterIsSeparator, None)
            self.treeView.expand_all()

        # done searching through the database, so close the progress bar
        self.progress.close()

        self.show()


    def iterIsSeparator(self, model, iter) :
        # return True only if the row is to be treated as a separator
        if self.model.get_value(iter, 1) == '':  # does the row have a GID?
            return True
        return False


    def selectIsAllowed(self, selection, model, path, isSelected, userData) :
        # return True/False depending on if the row being selected is a leaf node
        iter = self.model.get_iter(path)
        if self.model.get_value(iter, 1) == '': # does the row have a GID?
            return False
        return True


    def rowSelectionChanged(self, selection) :
        state = selection.count_selected_rows() > 0
        self.tagcombo.set_sensitive(state)
        self.tagapply.set_sensitive(state)


    def rowActivated(self, treeView, path, column) :
        # first we need to check that the row corresponds to a person
        iter = self.model.get_iter(path)
        personGid = self.model.get_value(iter, 1)
        familyGid = self.model.get_value(iter, 4)

        if familyGid != '': # do we have a family?
            # get the parent family for this person
            family = self.db.get_family_from_gramps_id(familyGid)
            if family:
                try:
                    EditFamily(self.dbstate, self.uistate, [], family)
                except WindowActiveError:
                    pass

        elif personGid != '': # do we have a person?
            # get the person that corresponds to this GID
            person = self.db.get_person_from_gramps_id(personGid)
            if person:
                try:
                    EditPerson(self.dbstate, self.uistate, [], person)
                except WindowActiveError:
                    pass

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC)


    def applyTagClicked(self, button) :
        progress    = None
        rows        = self.treeSelection.count_selected_rows()
        tag_name    = str(self.tagcombo.get_active_text())

        # start the db transaction
        with DbTxn("Tag not related", self.db) as transaction:

            tag = self.db.get_tag_from_name(tag_name)
            if not tag:
                # create the tag if it doesn't already exist
                tag = Tag()
                tag.set_name(tag_name)
                tag.set_priority(self.db.get_number_of_tags())
                tag_handle = self.db.add_tag(tag, transaction)
            else:
                tag_handle = tag.get_handle()

            # if more than 1 person is selected, use a progress indicator
            if rows > 1:
                progress = ProgressMeter(self.title,_('Starting'),
                                         parent=self.window)
                progress.set_pass(
                    # translators: leave all/any {...} untranslated
                    #TRANS: no singular form needed, as rows is always > 1
                    ngettext("Setting tag for {number_of} person",
                             "Setting tag for {number_of} people",
                             rows).format(number_of=rows),
                    rows)


            # iterate through all of the selected rows
            (model, paths) = self.treeSelection.get_selected_rows()

            for path in paths:
                if progress:
                    progress.step()

                # for the current row, get the GID and the person from the database
                iter        = self.model.get_iter(path)
                personGid   = self.model.get_value(iter, 1)
                person      = self.db.get_person_from_gramps_id(personGid)

                # add the tag to the person
                person.add_tag(tag_handle)

                # save this change
                self.db.commit_person(person, transaction)


        # refresh the tags column
        self.treeView.set_model(None)
        for path in paths:
            iter        = self.model.get_iter(path)
            personGid   = self.model.get_value(iter, 1)
            person      = self.db.get_person_from_gramps_id(personGid)
            self.model.set_value(iter, 3, self.get_tag_list(person))
        self.treeView.set_model(self.model)
        self.treeView.expand_all()

        if progress:
            progress.close()

    def findRelatedPeople(self) :

        self.progress.set_pass(
            # translators: leave all/any {...} untranslated
            #TRANS: No singular form is needed.
            ngettext("Finding relationships between {number_of} person",
                     "Finding relationships between {number_of} people",
                     self.numberOfPeopleInDatabase
                    ).format(number_of=self.numberOfPeopleInDatabase),
            self.numberOfPeopleInDatabase)

        # as long as we have people we haven't processed yet, keep looping
        while len(self.handlesOfPeopleToBeProcessed) > 0:
            handle = self.handlesOfPeopleToBeProcessed.pop()

### DEBUG DEBUG DEBUG
#            if len(self.handlesOfPeopleAlreadyProcessed) > 50:
#                break
###

            # see if we've already processed this person
            if handle in self.handlesOfPeopleAlreadyProcessed:
                continue

            person = self.db.get_person_from_handle(handle)

            # if we get here, then we're dealing with someone new
            self.progress.step()

            # remember that we've now seen this person
            self.handlesOfPeopleAlreadyProcessed.add(handle)

            # we have 4 things to do:  find (1) spouses, (2) parents, siblings(3), and (4) children

            # step 1 -- spouses
            for familyHandle in person.get_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                spouseHandle = utils.find_spouse(person, family)
                if spouseHandle and \
                  spouseHandle not in self.handlesOfPeopleAlreadyProcessed:
                    self.handlesOfPeopleToBeProcessed.add(spouseHandle)

            # step 2 -- parents
            for familyHandle in person.get_parent_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                fatherHandle = family.get_father_handle()
                motherHandle = family.get_mother_handle()
                if fatherHandle and \
                  fatherHandle not in self.handlesOfPeopleAlreadyProcessed:
                    self.handlesOfPeopleToBeProcessed.add(fatherHandle)
                if motherHandle and \
                  motherHandle not in self.handlesOfPeopleAlreadyProcessed:
                    self.handlesOfPeopleToBeProcessed.add(motherHandle)

            # step 3 -- siblings
            for familyHandle in person.get_parent_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                for childRef in family.get_child_ref_list():
                    childHandle = childRef.ref
                    if childHandle and \
                      childHandle not in self.handlesOfPeopleAlreadyProcessed:
                        self.handlesOfPeopleToBeProcessed.add(childHandle)

            # step 4 -- children
            for familyHandle in person.get_family_handle_list():
                family = self.db.get_family_from_handle(familyHandle)
                for childRef in family.get_child_ref_list():
                    childHandle = childRef.ref
                    if childHandle and \
                      childHandle not in self.handlesOfPeopleAlreadyProcessed:
                        self.handlesOfPeopleToBeProcessed.add(childHandle)


    def findUnrelatedPeople(self) :

        # update our numbers
        self.numberOfRelatedPeople = len(self.handlesOfPeopleAlreadyProcessed)
        self.numberOfUnrelatedPeople = (self.numberOfPeopleInDatabase -
                                        self.numberOfRelatedPeople)

        if self.numberOfUnrelatedPeople > 0:
            # we have at least 1 "unrelated" person to find

            self.progress.set_pass(
                # translators: leave all/any {...} untranslated
                ngettext("Looking for {number_of} person",
                         "Looking for {number_of} people",
                         self.numberOfUnrelatedPeople
                        ).format(number_of=self.numberOfUnrelatedPeople),
                self.numberOfPeopleInDatabase)

            # loop through everyone in the database
            for handle in self.db.iter_person_handles():

                self.progress.step()

                # if this person is related, then skip to the next one
                if handle in self.handlesOfPeopleAlreadyProcessed:
                    continue

### DEBUG DEBUG DEBUG
#                if len(self.handlesOfPeopleNotRelated) > 10:
#                    break
###

                # if we get here, we have someone who is "not related"
                self.handlesOfPeopleNotRelated.add(handle)


    def populateModel(self) :

        self.progress.set_pass(
            # translators: leave all/any {...} untranslated
            ngettext("Looking up the name of {number_of} person",
                     "Looking up the names of {number_of} people",
                     self.numberOfUnrelatedPeople
                    ).format(number_of=self.numberOfUnrelatedPeople),
            self.numberOfUnrelatedPeople)

        # loop through the entire list of unrelated people
        for handle in self.handlesOfPeopleNotRelated:
            self.progress.step()
            person      = self.db.get_person_from_handle(handle)
            primaryname = person.get_primary_name()
            surname     = primaryname.get_surname()
            name        = primaryname.get_name()
            gid         = person.get_gramps_id()

            # Retrieve the sorted tag list
            tag_list = self.get_tag_list(person)

            # find the names of the parents
            familygid   = ''
            parentNames = ''
            parentFamilyHandle = person.get_main_parents_family_handle()
            if parentFamilyHandle:
                parentFamily = self.db.get_family_from_handle(parentFamilyHandle)
                familygid    = parentFamily.get_gramps_id()
                fatherName   = None
                motherName   = None
                fatherHandle = parentFamily.get_father_handle()
                if fatherHandle:
                    father      = self.db.get_person_from_handle(fatherHandle)
                    fatherName  = father.get_primary_name().get_first_name()
                motherHandle = parentFamily.get_mother_handle()
                if motherHandle:
                    mother      = self.db.get_person_from_handle(motherHandle)
                    motherName  = mother.get_primary_name().get_first_name()

                # now that we have the names, come up with a label we can use
                if fatherName:
                    parentNames += fatherName
                if fatherName and motherName:
                    parentNames += ' & '
                if motherName:
                    parentNames += motherName

            # get the surname node (or create it if it doesn't exist)

            # start with the root
            iter = self.model.get_iter_first()
            # look for a node with a matching surname
            while iter:
                if self.model.get_value(iter, 0) == surname:
                    break;
                iter = self.model.iter_next(iter)

            # if we don't have a valid iter, then create a new top-level node
            if not iter:
                iter = self.model.append(None, [surname, '', '', '', ''])

            # finally, we now get to add this person to the model
            self.model.append(iter, [name, gid, parentNames, tag_list,
                                     familygid])

    def build_menu_names(self, obj):
        return (self.title, None)

    def get_tag_list(self, person):
        """
        Return a sorted list of tag names for the given person.
        """
        tags = []
        for handle in person.get_tag_list():
            tag = self.db.get_tag_from_handle(handle)
            tags.append(tag.get_name())
        tags.sort(key=glocale.sort_key)
        return ', '.join(tags)
Exemple #51
0
class PatchNames(tool.BatchTool, ManagedWindow):
    titleid = 1
    nickid = 2
    pref1id = 3
    compid = 4

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _('Name and title extraction tool')
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        winprefix = Gtk.Dialog(
            _("Default prefix and connector settings"), self.uistate.window,
            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            (_('_OK'), Gtk.ResponseType.ACCEPT))

        winprefix.vbox.set_spacing(5)
        hboxpref = Gtk.Box()
        label = Gtk.Label(label=_('Prefixes to search for:'))
        hboxpref.pack_start(label, False, False, 5)
        self.prefixbox = Gtk.Entry()
        self.prefixbox.set_text(', '.join(PREFIX_LIST))
        hboxpref.pack_start(self.prefixbox, True, True, 0)
        winprefix.vbox.pack_start(hboxpref, True, True, 0)
        hboxcon = Gtk.Box()
        label = Gtk.Label(label=_('Connectors splitting surnames:'))
        hboxcon.pack_start(label, False, False, 5)
        self.conbox = Gtk.Entry()
        self.conbox.set_text(', '.join(CONNECTOR_LIST))
        hboxcon.pack_start(self.conbox, True, True, 0)
        winprefix.vbox.pack_start(hboxcon, True, True, 0)
        hboxconns = Gtk.Box()
        label = Gtk.Label(label=_('Connectors not splitting surnames:'))
        hboxconns.pack_start(label, False, False, 5)
        self.connsbox = Gtk.Entry()
        self.connsbox.set_text(', '.join(CONNECTOR_LIST_NONSPLIT))
        hboxconns.pack_start(self.connsbox, True, True, 0)
        winprefix.vbox.pack_start(hboxconns, True, True, 0)
        winprefix.show_all()
        winprefix.resize(700, 100)

        response = winprefix.run()
        self.prefix_list = self.prefixbox.get_text().split(',')
        self.prefix_list = list(map(strip, self.prefix_list))
        self.prefixbox = None
        self.connector_list = self.conbox.get_text().split(',')
        self.connector_list = list(map(strip, self.connector_list))
        self.conbox = None
        self.connector_list_nonsplit = self.connsbox.get_text().split(',')
        self.connector_list_nonsplit = list(
            map(strip, self.connector_list_nonsplit))
        self.connsbox = None

        # Find a prefix in the first_name
        self._fn_prefix_re = re.compile(
            "(\S+)\s+(%s)\s*$" % '|'.join(self.prefix_list), re.IGNORECASE)

        # Find a prefix in the surname
        self._sn_prefix_re = re.compile(
            "^\s*(%s)\s+(.+)" % '|'.join(self.prefix_list), re.IGNORECASE)
        # Find a connector in the surname
        self._sn_con_re = re.compile(
            "^\s*(.+)\s+(%s)\s+(.+)" % '|'.join(self.connector_list),
            re.IGNORECASE)
        winprefix.destroy()

        self.cb = callback
        self.handle_to_action = {}

        self.progress = ProgressMeter(  # parent-OK
            _('Extracting Information from Names'),
            '',
            parent=self.uistate.window)
        self.progress.set_pass(_('Analyzing names'),
                               self.db.get_number_of_people())

        for person in self.db.iter_people():
            key = person.handle
            name = person.get_primary_name()
            first = name.get_first_name()
            sname = name.get_surname()

            old_prefix = []
            old_surn = []
            old_con = []
            old_prim = []
            old_orig = []
            for surn in name.get_surname_list():
                old_prefix.append(surn.get_prefix())
                old_surn.append(surn.get_surname())
                old_con.append(surn.get_connector())
                old_prim.append(surn.get_primary())
                old_orig.append(surn.get_origintype())

            if name.get_title():
                old_title = [name.get_title()]
            else:
                old_title = []
            new_title = []

            match = _title_re.match(first)
            while match:
                groups = match.groups()
                first = groups[1]
                new_title.append(groups[0])
                match = _title_re.match(first)
            matchnick = _nick_re.match(first)

            if new_title:
                titleval = (" ".join(old_title + new_title), first)
                if key in self.handle_to_action:
                    self.handle_to_action[key][self.titleid] = titleval
                else:
                    self.handle_to_action[key] = {self.titleid: titleval}
            elif matchnick:
                # we check for nick, which changes given name like title
                groups = matchnick.groups()
                nickval = (groups[0], groups[1])
                if key in self.handle_to_action:
                    self.handle_to_action[key][self.nickid] = nickval
                else:
                    self.handle_to_action[key] = {self.nickid: nickval}
            else:
                # Try to find the name prefix in the given name, also this
                # changes given name
                match = self._fn_prefix_re.match(first)
                if match:
                    groups = match.groups()
                    if old_prefix[0]:
                        # Put the found prefix before the old prefix
                        new_prefix = " ".join([groups[1], old_prefix[0]])
                    else:
                        new_prefix = groups[1]
                    pref1val = (groups[0], new_prefix, groups[1])
                    if key in self.handle_to_action:
                        self.handle_to_action[key][self.pref1id] = pref1val
                    else:
                        self.handle_to_action[key] = {self.pref1id: pref1val}

            #check for Gedcom import of compound surnames
            if len(old_surn) == 1 and old_con[0] == '':
                prefixes = old_prefix[0].split(',')
                surnames = old_surn[0].split(',')
                if len(prefixes) > 1 and len(prefixes) == len(surnames):
                    #assume a list of prefix and a list of surnames
                    prefixes = list(map(strip, prefixes))
                    surnames = list(map(strip, surnames))
                    primaries = [False] * len(prefixes)
                    primaries[0] = True
                    origs = []
                    for ind in range(len(prefixes)):
                        origs.append(NameOriginType())
                    origs[0] = old_orig[0]
                    compoundval = (surnames, prefixes, [''] * len(prefixes),
                                   primaries, origs)
                    if key in self.handle_to_action:
                        self.handle_to_action[key][self.compid] = compoundval
                    else:
                        self.handle_to_action[key] = {self.compid: compoundval}
                    #we cannot check compound surnames, so continue the loop
                    continue

            # Next, try to split surname in compounds: prefix surname connector
            found = False
            new_prefix_list = []
            new_surname_list = []
            new_connector_list = []
            new_prim_list = []
            new_orig_list = []
            ind = 0
            cont = True
            for pref, surn, con, prim, orig in zip(old_prefix, old_surn,
                                                   old_con, old_prim,
                                                   old_orig):
                surnval = surn.split()
                if surnval == []:
                    new_prefix_list.append(pref)
                    new_surname_list.append('')
                    new_connector_list.append(con)
                    new_prim_list.append(prim)
                    new_orig_list.append(orig)
                    cont = False
                    continue
                val = surnval.pop(0)
                while cont:
                    new_prefix_list.append(pref)
                    new_surname_list.append('')
                    new_connector_list.append(con)
                    new_prim_list.append(prim)
                    new_orig_list.append(orig)

                    while cont and (val.lower() in self.prefix_list):
                        found = True
                        if new_prefix_list[-1]:
                            new_prefix_list[-1] += ' ' + val
                        else:
                            new_prefix_list[-1] = val
                        try:
                            val = surnval.pop(0)
                        except IndexError:
                            val = ''
                            cont = False
                    #after prefix we have a surname
                    if cont:
                        new_surname_list[-1] = val
                        try:
                            val = surnval.pop(0)
                        except IndexError:
                            val = ''
                            cont = False
                    #if value after surname indicates continue, then continue
                    while cont and (val.lower()
                                    in self.connector_list_nonsplit):
                        #add this val to the current surname
                        new_surname_list[-1] += ' ' + val
                        try:
                            val = surnval.pop(0)
                        except IndexError:
                            val = ''
                            cont = False
                    # if previous is non-splitting connector, then add new val to
                    # current surname
                    if cont and (new_surname_list[-1].split()[-1].lower()
                                 in self.connector_list_nonsplit):
                        new_surname_list[-1] += ' ' + val
                        try:
                            val = surnval.pop(0)
                        except IndexError:
                            val = ''
                            cont = False
                    #if next is a connector, add it to the surname
                    if cont and val.lower() in self.connector_list:
                        found = True
                        if new_connector_list[-1]:
                            new_connector_list[-1] = ' ' + val
                        else:
                            new_connector_list[-1] = val
                        try:
                            val = surnval.pop(0)
                        except IndexError:
                            val = ''
                            cont = False
                    #initialize for a next surname in case there are still
                    #val
                    if cont:
                        found = True  # we split surname
                        pref = ''
                        con = ''
                        prim = False
                        orig = NameOriginType()
                ind += 1
            if found:
                compoundval = (new_surname_list, new_prefix_list,
                               new_connector_list, new_prim_list,
                               new_orig_list)
                if key in self.handle_to_action:
                    self.handle_to_action[key][self.compid] = compoundval
                else:
                    self.handle_to_action[key] = {self.compid: compoundval}

            self.progress.step()

        if self.handle_to_action:
            self.display()
        else:
            self.progress.close()
            self.close()
            OkDialog(
                _('No modifications made'),  # parent-OK
                _("No titles, nicknames or prefixes were found"),
                parent=self.uistate.window)

    def build_menu_names(self, obj):
        return (self.label, None)

    def toggled(self, cell, path_string):
        path = tuple(map(int, path_string.split(':')))
        row = self.model[path]
        row[0] = not row[0]
        self.model.row_changed(path, row.iter)

    def display(self):

        self.top = Glade()
        window = self.top.toplevel
        self.top.connect_signals({
            "destroy_passed_object": self.close,
            "on_ok_clicked": self.on_ok_clicked,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_event": self.close,
        })

        self.list = self.top.get_object("list")
        self.set_window(window, self.top.get_object('title'), self.label)

        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING)

        r = Gtk.CellRendererToggle()
        r.connect('toggled', self.toggled)
        c = Gtk.TreeViewColumn(_('Select'), r, active=0)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('ID'), Gtk.CellRendererText(), text=1)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Type'), Gtk.CellRendererText(), text=2)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Value'), Gtk.CellRendererText(), text=3)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Current Name'),
                               Gtk.CellRendererText(),
                               text=4)
        self.list.append_column(c)

        self.list.set_model(self.model)

        self.nick_hash = {}
        self.title_hash = {}
        self.prefix1_hash = {}
        self.compound_hash = {}

        self.progress.set_pass(_('Building display'),
                               len(list(self.handle_to_action.keys())))

        for key, data in self.handle_to_action.items():
            p = self.db.get_person_from_handle(key)
            gid = p.get_gramps_id()
            if self.nickid in data:
                given, nick = data[self.nickid]
                handle = self.model.append()
                self.model.set_value(handle, 0, 1)
                self.model.set_value(handle, 1, gid)
                self.model.set_value(handle, 2, _('Nickname'))
                self.model.set_value(handle, 3, nick)
                self.model.set_value(handle, 4,
                                     p.get_primary_name().get_name())
                self.nick_hash[key] = handle

            if self.titleid in data:
                title, given = data[self.titleid]
                handle = self.model.append()
                self.model.set_value(handle, 0, 1)
                self.model.set_value(handle, 1, gid)
                self.model.set_value(handle, 2, _('Person|Title'))
                self.model.set_value(handle, 3, title)
                self.model.set_value(handle, 4,
                                     p.get_primary_name().get_name())
                self.title_hash[key] = handle

            if self.pref1id in data:
                given, prefixtotal, new_prefix = data[self.pref1id]
                handle = self.model.append()
                self.model.set_value(handle, 0, 1)
                self.model.set_value(handle, 1, gid)
                self.model.set_value(handle, 2, _('Prefix in given name'))
                self.model.set_value(handle, 3, prefixtotal)
                self.model.set_value(handle, 4,
                                     p.get_primary_name().get_name())
                self.prefix1_hash[key] = handle

            if self.compid in data:
                surn_list, pref_list, con_list, prims, origs = data[
                    self.compid]
                handle = self.model.append()
                self.model.set_value(handle, 0, 1)
                self.model.set_value(handle, 1, gid)
                self.model.set_value(handle, 2, _('Compound surname'))
                newval = ''
                for sur, pre, con in zip(surn_list, pref_list, con_list):
                    if newval:
                        newval += '-['
                    else:
                        newval = '['
                    newval += pre + ',' + sur
                    if con:
                        newval += ',' + con + ']'
                    else:
                        newval += ']'
                self.model.set_value(handle, 3, newval)
                self.model.set_value(handle, 4,
                                     p.get_primary_name().get_name())
                self.compound_hash[key] = handle

            self.progress.step()

        self.progress.close()
        self.show()

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def on_ok_clicked(self, obj):
        with DbTxn(_("Extract information from names"), self.db,
                   batch=True) as trans:
            self.db.disable_signals()

            for key, data in self.handle_to_action.items():
                p = self.db.get_person_from_handle(key)
                if self.nickid in data:
                    modelhandle = self.nick_hash[key]
                    val = self.model.get_value(modelhandle, 0)
                    if val:
                        given, nick = data[self.nickid]
                        name = p.get_primary_name()
                        name.set_first_name(given.strip())
                        name.set_nick_name(nick.strip())

                if self.titleid in data:
                    modelhandle = self.title_hash[key]
                    val = self.model.get_value(modelhandle, 0)
                    if val:
                        title, given = data[self.titleid]
                        name = p.get_primary_name()
                        name.set_first_name(given.strip())
                        name.set_title(title.strip())

                if self.pref1id in data:
                    modelhandle = self.prefix1_hash[key]
                    val = self.model.get_value(modelhandle, 0)
                    if val:
                        given, prefixtotal, prefix = data[self.pref1id]
                        name = p.get_primary_name()
                        name.set_first_name(given.strip())
                        oldpref = name.get_surname_list()[0].get_prefix(
                        ).strip()
                        if oldpref == '' or oldpref == prefix.strip():
                            name.get_surname_list()[0].set_prefix(prefix)
                        else:
                            name.get_surname_list()[0].set_prefix(
                                '%s %s' % (prefix, oldpref))

                if self.compid in data:
                    modelhandle = self.compound_hash[key]
                    val = self.model.get_value(modelhandle, 0)
                    if val:
                        surns, prefs, cons, prims, origs = data[self.compid]
                        name = p.get_primary_name()
                        new_surn_list = []
                        for surn, pref, con, prim, orig in zip(
                                surns, prefs, cons, prims, origs):
                            new_surn_list.append(Surname())
                            new_surn_list[-1].set_surname(surn.strip())
                            new_surn_list[-1].set_prefix(pref.strip())
                            new_surn_list[-1].set_connector(con.strip())
                            new_surn_list[-1].set_primary(prim)
                            new_surn_list[-1].set_origintype(orig)
                        name.set_surname_list(new_surn_list)

                self.db.commit_person(p, trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        self.close()
        self.cb()
Exemple #52
0
class ReorderIds(tool.BatchTool):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        db = dbstate.db
        self.uistate = uistate
        if uistate:
            self.progress = ProgressMeter(_('Reordering Gramps IDs'), '')
        else:
            print(_("Reordering Gramps IDs..."))

        with DbTxn(_("Reorder Gramps IDs"), db, batch=True) as self.trans:
            db.disable_signals()

            if uistate:
                self.progress.set_pass(_('Reordering People IDs'),
                                       db.get_number_of_people())
            self.reorder(Person, db.get_person_from_gramps_id,
                         db.get_person_from_handle,
                         db.find_next_person_gramps_id, db.person_map,
                         db.commit_person, db.person_prefix)

            if uistate:
                self.progress.set_pass(_('Reordering Family IDs'),
                                       db.get_number_of_families())
            self.reorder(Family, db.get_family_from_gramps_id,
                         db.get_family_from_handle,
                         db.find_next_family_gramps_id, db.family_map,
                         db.commit_family, db.family_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Event IDs'),
                                       db.get_number_of_events())
            self.reorder(Event, db.get_event_from_gramps_id,
                         db.get_event_from_handle,
                         db.find_next_event_gramps_id, db.event_map,
                         db.commit_event, db.event_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Media Object IDs'),
                                       db.get_number_of_media_objects())
            self.reorder(MediaObject, db.get_object_from_gramps_id,
                         db.get_object_from_handle,
                         db.find_next_object_gramps_id, db.media_map,
                         db.commit_media_object, db.mediaobject_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Source IDs'),
                                       db.get_number_of_sources())
            self.reorder(Source, db.get_source_from_gramps_id,
                         db.get_source_from_handle,
                         db.find_next_source_gramps_id, db.source_map,
                         db.commit_source, db.source_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Citation IDs'),
                                       db.get_number_of_citations())
            self.reorder(Citation, db.get_citation_from_gramps_id,
                         db.get_citation_from_handle,
                         db.find_next_citation_gramps_id, db.citation_map,
                         db.commit_citation, db.citation_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Place IDs'),
                                       db.get_number_of_places())
            self.reorder(Place, db.get_place_from_gramps_id,
                         db.get_place_from_handle,
                         db.find_next_place_gramps_id, db.place_map,
                         db.commit_place, db.place_prefix)
            if uistate:
                self.progress.set_pass(_('Reordering Repository IDs'),
                                       db.get_number_of_repositories())
            self.reorder(Repository, db.get_repository_from_gramps_id,
                         db.get_repository_from_handle,
                         db.find_next_repository_gramps_id, db.repository_map,
                         db.commit_repository, db.repository_prefix)
            #add reorder notes ID
            if uistate:
                self.progress.set_pass(_('Reordering Note IDs'),
                                       db.get_number_of_notes())
            self.reorder(Note, db.get_note_from_gramps_id,
                         db.get_note_from_handle, db.find_next_note_gramps_id,
                         db.note_map, db.commit_note, db.note_prefix)
            if uistate:
                self.progress.close()
            else:
                print(_("Done."))

        db.enable_signals()
        db.request_rebuild()

    def reorder(self, class_type, find_from_id, find_from_handle, find_next_id,
                table, commit, prefix):
        dups = []
        newids = {}

        formatmatch = _parseformat.match(prefix)

        for handle in list(table.keys()):
            if self.uistate:
                self.progress.step()

            sdata = table[handle]

            obj = class_type()
            obj.unserialize(sdata)
            gramps_id = obj.get_gramps_id()
            # attempt to extract integer, if we can't, treat it as a
            # duplicate

            try:
                match = _findint.match(gramps_id)
                if match:
                    # get the integer, build the new handle. Make sure it
                    # hasn't already been chosen. If it has, put this
                    # in the duplicate handle list

                    index = match.groups()[0]

                    if formatmatch:
                        if int(index) > int(
                                "9" * int(formatmatch.groups()[0])):
                            newgramps_id = find_next_id()
                        else:
                            newgramps_id = prefix % int(index)
                    else:
                        # the prefix does not contain a number after %, eg I%d
                        newgramps_id = prefix % int(index)

                    if newgramps_id == gramps_id:
                        if newgramps_id in newids:
                            dups.append(obj.get_handle())
                        else:
                            newids[newgramps_id] = gramps_id
                    elif find_from_id(newgramps_id) is not None:
                        dups.append(obj.get_handle())
                    else:
                        obj.set_gramps_id(newgramps_id)
                        commit(obj, self.trans)
                        newids[newgramps_id] = gramps_id
                else:
                    dups.append(handle)
            except:
                dups.append(handle)

        # go through the duplicates, looking for the first available
        # handle that matches the new scheme.

        if self.uistate:
            self.progress.set_pass(_('Finding and assigning unused IDs'),
                                   len(dups))
        for handle in dups:
            if self.uistate:
                self.progress.step()
            obj = find_from_handle(handle)
            obj.set_gramps_id(find_next_id())
            commit(obj, self.trans)
Exemple #53
0
class DownloadMedia(tool.Tool, ManagedWindow):
    """
    Gramplet that downloads media from the internet.
    """

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _('Download media')
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')
        tool.Tool.__init__(self, dbstate, options_class, name)

        self.num_downloads = 0
        dialog = self.display()
        response = dialog.run()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            self.on_ok_clicked()
            OkDialog(_('Media downloaded'),
                     _("%d media files downloaded") % self.num_downloads)

        self.close()

    def display(self):
        """
        Constructs the GUI, consisting of a message, and fields to enter the
        name and password (commented out for now)
        """


        # GUI setup:
        dialog = Gtk.Dialog(_("Download media tool"),
                                self.uistate.window,
                                Gtk.DialogFlags.MODAL|
                                Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                (Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
                                 Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
        label = Gtk.Label(_("Make sure you are connected to the internet "
                            "before starting this tool."))
        label.set_line_wrap(True)
        vbox = Gtk.VBox()
        vbox.pack_start(label, True, True, 0)

#        hbox1 = Gtk.HBox()
#        label_name = Gtk.Label(_("Name") + ":")
#        self.name_entry = Gtk.Entry()
#        self.name_entry.set_text("%s" % name)
#        hbox1.pack_start(label_name, False, False, 0)
#        hbox1.pack_start(self.name_entry, True, True, 0)
#        vbox.pack_start(hbox1, False)
#
#        hbox2 = Gtk.HBox()
#        label_password = Gtk.Label(_("Password") + ":")
#        self.password_entry = Gtk.Entry()
#        self.password_entry.set_text("%s" % password)
#        hbox2.pack_start(label_password, False, False, 0)
#        hbox2.pack_start(self.password_entry, True, True, 0)
#        vbox.pack_start(hbox2, False)

        dialog.vbox.set_spacing(10)
        dialog.vbox.pack_start(vbox, True, True, 0)
        dialog.show_all()
        return dialog

    def on_ok_clicked(self):
        """
        Method that is run when you click the OK button.
        """
        downloaded = {}

        # Get a directory to put the media files in. If the media path in
        # preferences is not just the user's home, then we will use that. If it
        # is the user's home, we create a new directory below that, so we don't
        # splatter files into home.
        media_path = self.db.get_mediapath()
        if media_path == USER_HOME or media_path == "" or media_path == None:
            media_path = os.path.join(USER_HOME, "mediadir")
        if not os.path.isdir(media_path):
            os.makedirs(media_path)

        # Many thanks to 'sirex' from whom I have taken the code he submitted as
        # part of bug 0003553: Import media files from GEDCOM
        file_pattern = re.compile(r'.*\.(png|jpg|jpeg|gif)$')

        def fetch_file(url, filename):
            LOG.debug("Downloading url %s to file %s" % (url, filename))
            fr = urlopen(url)
            fw = open(filename, 'wb')
            for block in fr:
                fw.write(block)
            fw.close()
            fr.close()

        self.progress = ProgressMeter(
            _('Downloading files'), '')
        self.progress.set_pass(_('Downloading files'),
                               self.db.get_number_of_media_objects())

        self.db.disable_signals()
        with DbTxn('Download files', self.db) as trans:
            for media_handle in self.db.media_map.keys():
                media = self.db.get_object_from_handle(media_handle)
                url = media.get_path()
                res = urlparse(url)
                LOG.debug(res)
                if res.scheme == "http" or res.scheme == "https":
                    if file_pattern.match(url):
                        if url in downloaded:
                            full_path = downloaded[url]
                        else:
                            filename = url.split('/')[-1]
                            full_path = os.path.join(media_path, filename)
                            fetch_file(url, full_path)
                            downloaded[url] = full_path
                            self.num_downloads += 1
                        media.set_path(full_path)
                        media.set_mime_type(get_type(full_path))
                        self.db.commit_media_object(media, trans)

                self.progress.step()

        self.db.enable_signals()
        self.db.request_rebuild()
        self.progress.close()
Exemple #54
0
class MergeCitations(tool.BatchTool,ManagedWindow):

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.user = user

        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.set_window(Gtk.Window(), Gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)

        if not self.fail:
            uistate.set_busy_cursor(True)
            self.run()
            uistate.set_busy_cursor(False)

    def run(self):

        top = Glade(toplevel="mergecitations")

        # retrieve options
        fields = self.options.handler.options_dict['fields']
        dont_merge_notes = self.options.handler.options_dict['dont_merge_notes']

        my_menu = Gtk.ListStore(str, object)
        for val in sorted(_val2label):
            my_menu.append([_val2label[val], val])

        self.notes_obj = top.get_object("notes")
        self.notes_obj.set_active(dont_merge_notes)
        self.notes_obj.show()

        self.menu = top.get_object("menu")
        self.menu.set_model(my_menu)
        self.menu.set_active(fields)

        window = top.toplevel
        window.set_transient_for(self.user.uistate.window)
        window.show()
#        self.set_window(window, top.get_object('title'),
#                        _('Merge citations'))
        self.set_window(window, top.get_object('title2'),
                        _("Notes, media objects and data-items of matching "
                          "citations will be combined."))
        self.setup_configs('interface.mergecitations', 700, 230)

        top.connect_signals({
            "on_merge_ok_clicked"   : self.on_merge_ok_clicked,
            "destroy_passed_object" : self.cancel,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_merge_event" : self.close,
            "on_delete_event"       : self.close,
            })

        self.show()

    def cancel(self, obj):
        """
        on cancel, update the saved values of the options.
        """
        fields = self.menu.get_model()[self.menu.get_active()][1]
        dont_merge_notes = int(self.notes_obj.get_active())
        LOG.debug("cancel fields %d dont_merge_notes %d" %
                  (fields, dont_merge_notes))

        self.options.handler.options_dict['fields'] = fields
        self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes
        # Save options
        self.options.handler.save_options()

        self.close(obj)

    def build_menu_names(self, obj):
        return (_("Tool settings"),_("Merge citations tool"))

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""

        display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC)

    def on_merge_ok_clicked(self, obj):
        """
        Performs the actual merge of citations
        (Derived from ExtractCity)
        """
        fields = self.menu.get_model()[self.menu.get_active()][1]
        dont_merge_notes = int(self.notes_obj.get_active())
        LOG.debug("fields %d dont_merge_notes %d" % (fields, dont_merge_notes))

        self.options.handler.options_dict['fields'] = fields
        self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes
        # Save options
        self.options.handler.save_options()

        self.progress = ProgressMeter(_('Checking Sources'), '',
                                      parent=self.window)
        self.progress.set_pass(_('Looking for citation fields'),
                               self.db.get_number_of_citations())

        db = self.dbstate.db

        db.disable_signals()
        num_merges = 0
        for handle in db.iter_source_handles():
            dict = {}
            citation_handle_list = list(db.find_backlink_handles(handle))
            for (class_name, citation_handle) in citation_handle_list:
                if class_name != Citation.__name__:
                    raise MergeError("Encountered an object of type %s "
                    "that has a citation reference." % class_name)

                citation = db.get_citation_from_handle(citation_handle)
                if citation is None:
                    continue
                key = citation.get_page()
                if fields != IGNORE_DATE and fields != IGNORE_BOTH:
                    key += "\n" + get_date(citation)
                if fields != IGNORE_CONFIDENCE and fields != IGNORE_BOTH:
                    key += "\n" + \
                        conf_strings[citation.get_confidence_level()]
                if key in dict and \
                    (not dont_merge_notes or len(citation.note_list) == 0):
                    citation_match_handle = dict[key]
                    citation_match = \
                        db.get_citation_from_handle(citation_match_handle)
                    try:
                        query = MergeCitationQuery(
                                self.dbstate, citation_match, citation)
                        query.execute()
                    except AssertionError:
                        print("Tool/Family Tree processing/MergeCitations", \
                        "citation1 gramps_id", citation_match.get_gramps_id(), \
                        "citation2 gramps_id", citation.get_gramps_id() , \
                        "citation backlink handles", \
                        list(db.find_backlink_handles(citation.get_handle())))
                    num_merges += 1
                elif (not dont_merge_notes or len(citation.note_list) == 0):
                    dict[key] = citation_handle
                self.progress.step()
        db.enable_signals()
        db.request_rebuild()
        self.progress.close()
        OkDialog(_("Number of merges done"),
                 # translators: leave all/any {...} untranslated
                 ngettext("{number_of} citation merged",
                          "{number_of} citations merged", num_merges
                         ).format(number_of=num_merges),
                 parent=self.window)
        self.close(obj)
Exemple #55
0
    def _createmap(self, place_x):
        """
        Create all markers for each people's event in the database which has
        a lat/lon.
        """
        dbstate = self.dbstate
        self.place_list = []
        self.places_found = []
        self.place_without_coordinates = []
        self.minlat = 0.0
        self.maxlat = 0.0
        self.minlon = 0.0
        self.maxlon = 0.0
        self.minyear = 9999
        self.maxyear = 0
        self.without = 0
        latitude = ""
        longitude = ""
        self.nbmarkers = 0
        self.nbplaces = 0
        self.remove_all_markers()
        self.message_layer.clear_messages()
        self.message_layer.clear_font_attributes()
        self.kml_layer.clear()
        self.no_show_places_in_status_bar = False
        _col = self._config.get
        self.plc_color = [
            (PlaceType.UNKNOWN, _col('geography.color.unknown')),
            (PlaceType.CUSTOM, _col('geography.color.custom')),
            (PlaceType.COUNTRY, _col('geography.color.country')),
            (PlaceType.STATE, _col('geography.color.state')),
            (PlaceType.COUNTY, _col('geography.color.county')),
            (PlaceType.CITY, _col('geography.color.city')),
            (PlaceType.PARISH, _col('geography.color.parish')),
            (PlaceType.LOCALITY, _col('geography.color.locality')),
            (PlaceType.STREET, _col('geography.color.street')),
            (PlaceType.PROVINCE, _col('geography.color.province')),
            (PlaceType.REGION, _col('geography.color.region')),
            (PlaceType.DEPARTMENT, _col('geography.color.department')),
            (PlaceType.NEIGHBORHOOD, _col('geography.color.neighborhood')),
            (PlaceType.DISTRICT, _col('geography.color.district')),
            (PlaceType.BOROUGH, _col('geography.color.borough')),
            (PlaceType.MUNICIPALITY, _col('geography.color.municipality')),
            (PlaceType.TOWN, _col('geography.color.town')),
            (PlaceType.VILLAGE, _col('geography.color.village')),
            (PlaceType.HAMLET, _col('geography.color.hamlet')),
            (PlaceType.FARM, _col('geography.color.farm')),
            (PlaceType.BUILDING, _col('geography.color.building')),
            (PlaceType.NUMBER, _col('geography.color.number'))
        ]
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 1'23"
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization
        # base "villes de france" : 38101 places :
        # gramps 3.4 python 2.7 (draw_markers are estimated when moving the map)
        # 38101 places: createmap: 04'32";
        #               create_markers: 0'04"; draw markers: N/A :: 0'03"
        # 65598 places: createmap: 10'03";
        #               create_markers: 0'07"; draw markers: N/A :: 0'05"
        # gramps 3.5 python 2.7 new marker layer
        # 38101 places: createmap: 03'09";
        #               create_markers: 0'01"; draw markers: 0'04"
        # 65598 places: createmap: 08'48";
        #               create_markers: 0'01"; draw markers: 0'07"
        _LOG.debug(
            "%s",
            time.strftime("start createmap : "
                          "%a %d %b %Y %H:%M:%S", time.gmtime()))
        self.custom_places()
        if self.show_all:
            self.show_all = False
            try:
                places_handle = dbstate.db.get_place_handles()
            except:
                return
            progress = ProgressMeter(self.window_name,
                                     can_cancel=False,
                                     parent=self.uistate.window)
            length = len(places_handle)
            progress.set_pass(_('Selecting all places'), length)
            for place_hdl in places_handle:
                place = dbstate.db.get_place_from_handle(place_hdl)
                self._create_one_place(place)
                progress.step()
            progress.close()
        elif self.generic_filter:
            user = self.uistate.viewmanager.user
            place_list = self.generic_filter.apply(dbstate.db, user=user)
            progress = ProgressMeter(self.window_name,
                                     can_cancel=False,
                                     parent=self.uistate.window)
            length = len(place_list)
            progress.set_pass(_('Selecting all places'), length)
            for place_handle in place_list:
                place = dbstate.db.get_place_from_handle(place_handle)
                self._create_one_place(place)
                progress.step()
            progress.close()
            # reset completely the filter. It will be recreated next time.
            self.generic_filter = None
        elif place_x != None:
            place = dbstate.db.get_place_from_handle(place_x)
            self._create_one_place(place)
            self.message_layer.add_message(
                _("Right click on the map and select 'show all places'"
                  " to show all known places with coordinates. "
                  "You can change the markers color depending on place type. "
                  "You can use filtering."))
            if place.get_latitude() != "" and place.get_longitude() != "":
                latitude, longitude = conv_lat_lon(place.get_latitude(),
                                                   place.get_longitude(),
                                                   "D.D8")
                if latitude and longitude:
                    self.osm.set_center_and_zoom(
                        float(latitude), float(longitude),
                        int(config.get("geography.zoom_when_center")))
        else:
            self.message_layer.add_message(
                _("Right click on the map and select 'show all places'"
                  " to show all known places with coordinates. "
                  "You can use the history to navigate on the map. "
                  "You can change the markers color depending on place type. "
                  "You can use filtering."))
        _LOG.debug(" stop createmap.")
        _LOG.debug(
            "%s",
            time.strftime("begin sort : "
                          "%a %d %b %Y %H:%M:%S", time.gmtime()))
        self.sort = sorted(self.place_list, key=operator.itemgetter(0))
        _LOG.debug(
            "%s",
            time.strftime("  end sort : "
                          "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.nbmarkers > 500:  # performance issue. Is it the good value ?
            self.message_layer.add_message(
                _("The place name in the status bar is disabled."))
            self.no_show_places_in_status_bar = True
        if self.nbplaces >= self._config.get("geography.max_places"):
            self.message_layer.set_font_attributes(None, None, "red")
            self.message_layer.add_message(
                _("The maximum number of places is reached (%d).") %
                self._config.get("geography.max_places"))
            self.message_layer.add_message(_("Some information are missing."))
            self.message_layer.add_message(
                _("Please, use filtering to reduce this number."))
            self.message_layer.add_message(
                _("You can modify this value in the geography option."))
            self.message_layer.add_message(
                _("In this case, it may take time to show all markers."))

        self._create_markers()
Exemple #56
0
class DownloadMedia(tool.Tool, ManagedWindow):
    """
    Gramplet that downloads media from the internet.
    """
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.user = user
        self.label = _('Download media')
        ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(Gtk.Window(), Gtk.Label(), '')
        tool.Tool.__init__(self, dbstate, options_class, name)

        self.num_downloads = 0
        dialog = self.display()
        response = dialog.run()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            self.on_ok_clicked()
            if hasattr(self.user.uistate, 'window'):
                parent_window = self.user.uistate.window
            else:
                parent_window = None
            OkDialog(_('Media downloaded'),
                     _("%d media files downloaded") % self.num_downloads,
                     parent=parent_window)
        self.close()

    def display(self):
        """
        Constructs the GUI, consisting of a message, and fields to enter the
        name and password (commented out for now)
        """

        # GUI setup:
        dialog = Gtk.Dialog(
            _("Download media tool"), self.uistate.window,
            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK,
             Gtk.ResponseType.ACCEPT))
        label = Gtk.Label(
            _("Make sure you are connected to the internet "
              "before starting this tool."))
        label.set_line_wrap(True)
        vbox = Gtk.VBox()
        vbox.pack_start(label, True, True, 0)

        #        hbox1 = Gtk.HBox()
        #        label_name = Gtk.Label(_("Name") + ":")
        #        self.name_entry = Gtk.Entry()
        #        self.name_entry.set_text("%s" % name)
        #        hbox1.pack_start(label_name, False, False, 0)
        #        hbox1.pack_start(self.name_entry, True, True, 0)
        #        vbox.pack_start(hbox1, False)
        #
        #        hbox2 = Gtk.HBox()
        #        label_password = Gtk.Label(_("Password") + ":")
        #        self.password_entry = Gtk.Entry()
        #        self.password_entry.set_text("%s" % password)
        #        hbox2.pack_start(label_password, False, False, 0)
        #        hbox2.pack_start(self.password_entry, True, True, 0)
        #        vbox.pack_start(hbox2, False)

        dialog.vbox.set_spacing(10)
        dialog.vbox.pack_start(vbox, True, True, 0)
        dialog.show_all()
        return dialog

    def on_ok_clicked(self):
        """
        Method that is run when you click the OK button.
        """
        downloaded = {}

        # Get a directory to put the media files in. If the media path in
        # preferences is not just the user's home, then we will use that. If it
        # is the user's home, we create a new directory below that, so we don't
        # splatter files into home.
        media_path = self.db.get_mediapath()
        if media_path == USER_HOME or media_path == "" or media_path == None:
            media_path = os.path.join(USER_HOME, "mediadir")
        if not os.path.isdir(media_path):
            os.makedirs(media_path)

        # Many thanks to 'sirex' from whom I have taken the code he submitted as
        # part of bug 0003553: Import media files from GEDCOM
        file_pattern = re.compile(r'.*\.(png|jpg|jpeg|gif)$')

        def fetch_file(url, filename):
            LOG.debug("Downloading url %s to file %s" % (url, filename))
            try:
                fr = urlopen(url)
            except HTTPError:
                return False
            try:
                fw = open(filename, 'wb')
            except:
                fr.close()
                return False
            for block in fr:
                fw.write(block)
            fw.close()
            fr.close()
            return True

        self.progress = ProgressMeter(_('Downloading files'), '')
        self.progress.set_pass(_('Downloading files'),
                               self.db.get_number_of_media())

        self.db.disable_signals()
        errors = ''
        with DbTxn('Download files', self.db) as trans:
            for media_handle in self.db.get_media_handles():
                media = self.db.get_media_from_handle(media_handle)
                url = media.get_path()
                res = urlparse(url)
                LOG.debug(res)
                if res.scheme == "http" or res.scheme == "https":
                    if file_pattern.match(url):
                        if url in downloaded:
                            full_path = downloaded[url]
                        else:
                            filename = url.split('/')[-1]
                            full_path = os.path.join(media_path, filename)
                            if not fetch_file(url, full_path):
                                errors += url + '\n'
                                continue
                            downloaded[url] = full_path
                            self.num_downloads += 1
                        media.set_path(full_path)
                        media.set_mime_type(get_type(full_path))
                        self.db.commit_media(media, trans)
                    else:
                        errors += url + '\n'

                self.progress.step()

        self.db.enable_signals()
        self.db.request_rebuild()
        self.progress.close()
        if errors:
            message = _("Media download errors detected")
            if hasattr(self.user.uistate, 'window'):
                parent_window = self.user.uistate.window
            else:
                parent_window = None
            self.user.info(message,
                           errors,
                           parent=parent_window,
                           monospaced=True)
Exemple #57
0
class ChangeNames(tool.BatchTool, ManagedWindow):

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _('Capitalization changes')
        self.cb = callback

        ManagedWindow.__init__(self,uistate,[],self.__class__)
        self.set_window(Gtk.Window(),Gtk.Label(),'')

        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
        if self.fail:
            return

        self.progress = ProgressMeter(_('Checking Family Names'),'')
        self.progress.set_pass(_('Searching family names'),
                               len(self.db.get_surname_list()))
        self.name_list = []

        for name in self.db.get_surname_list():
            name.strip()
            namesplitSP= name.split()
            lSP = len(namesplitSP)
            namesplitHY= name.split('-')
            lHY = len(namesplitHY)
            if lSP == lHY == 1:
                if name != name.capitalize():
                    # Single surname without hyphen(s)
                    self.name_list.append(name)
            #if lSP == 1 and lHY > 1:
                #print "LSP==1", name, name.capitalize()
                #if name != name.capitalize():
                    # Single surname with hyphen(s)
                    #self.name_list.append(name)
            if lSP>1 and lHY == 1:
                # more than one string in surname but no hyphen
                # check if first string is in prefix_list, if so test for cap in rest
                s1 = 0
                if namesplitSP[0].lower() in prefix_list:
                    s1 = 1
                for x in range(len(namesplitSP)-s1):
                    # check if any subsurname is not cap
                    notcap = False
                    if namesplitSP[s1+x] != namesplitSP[s1+x].capitalize():
                        notcap = True
                        break
                if notcap:
                    # Multiple surnames possibly after prefix
                    self.name_list.append(name)
            if lHY > 1:
                # more than one string in surname but hyphen(s) exists
                # check if first string is in prefix_list, if so test for cap
                if namesplitSP[0].lower() in prefix_list:
                    namesplitHY[0] = namesplitHY[0].replace(namesplitSP[0],'').strip()
                for x in range(len(namesplitHY)):
                    # check if any subsurname is not cap
                    notcap = False
                    if namesplitHY[x] != namesplitHY[x].capitalize():
                        notcap = True
                        break
                if notcap:
                    # Multiple surnames possibly after frefix
                    self.name_list.append(name)

            if uistate:
                self.progress.step()

        if self.name_list:
            self.display()
        else:
            self.progress.close()
            self.close()
            OkDialog(_('No modifications made'),
                     _("No capitalization changes were detected."),
                     parent=uistate.window)

    def name_cap(self, name):
        name.strip()
        namesplitSP = name.split()
        lSP = len(namesplitSP)
        lHY = len(name.split('-'))
        namesep = ' '
        if lHY > 1:
            namesep = '-'
            namesplitSP = name.replace(namesep,' ').split()
            lSP= len(namesplitSP)
        if lSP == lHY == 1:
            #if name != name.capitalize():
            # Single surname without space(s) or hyphen(s), normal case
            return name.capitalize()
        else:
            # more than one string in surname but no hyphen
            # check if first string is in prefix_list, if so CAP the rest
            # Names like (von) Kohl(-)Brandt
            result = ""
            s1 = 0
            if namesplitSP[0].lower() in prefix_list:
                s1 = 1
                result = namesplitSP[0].lower()+ ' '
            for x in range(lSP-s1):
                # CAP all subsurnames
                result = result + namesplitSP[s1+x].capitalize() + namesep
            return result[:-1]

    def display(self):

        self.top = Glade()
        window = self.top.toplevel
        self.top.connect_signals({
            "destroy_passed_object" : self.close,
            "on_ok_clicked" : self.on_ok_clicked,
            "on_help_clicked" : self.on_help_clicked,
            "on_delete_event"   : self.close,
            })

        self.list = self.top.get_object("list")
        self.set_window(window,self.top.get_object('title'),self.label)

        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING)

        r = Gtk.CellRendererToggle()
        r.connect('toggled',self.toggled)
        c = Gtk.TreeViewColumn(_('Select'),r,active=0)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Original Name'),
                               Gtk.CellRendererText(),text=1)
        self.list.append_column(c)

        c = Gtk.TreeViewColumn(_('Capitalization Change'),
                               Gtk.CellRendererText(),text=2)
        self.list.append_column(c)

        self.list.set_model(self.model)

        self.iter_list = []
        self.progress.set_pass(_('Building display'),len(self.name_list))
        for name in self.name_list:
            handle = self.model.append()
            self.model.set_value(handle,0,True)
            self.model.set_value(handle,1, name)
            namecap = self.name_cap(name)
            self.model.set_value(handle,2, namecap)
            self.iter_list.append(handle)
            self.progress.step()
        self.progress.close()

        self.show()

    def toggled(self,cell,path_string):
        path = tuple(map(int, path_string.split(':')))
        row = self.model[path]
        row[0] = not row[0]

    def build_menu_names(self, obj):
        return (self.label,None)

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC)

    def on_ok_clicked(self, obj):
        with DbTxn(_("Capitalization changes"), self.db, batch=True
                   ) as self.trans:
            self.db.disable_signals()
            changelist = set(self.model.get_value(node,1)
                            for node in self.iter_list
                                if self.model.get_value(node,0))

            #with self.db.get_person_cursor(update=True, commit=True) as cursor:
            #  for handle, data in cursor:
            for handle in self.db.get_person_handles(False):
                person = self.db.get_person_from_handle(handle)
                #person = Person(data)
                change = False
                for name in [person.get_primary_name()] + person.get_alternate_names():
                    sname = find_surname_name(handle, name.serialize())
                    if sname in changelist:
                        change = True
                        for surn in name.get_surname_list():
                            sname = self.name_cap(surn.get_surname())
                            surn.set_surname(sname)
                if change:
                    #cursor.update(handle, person.serialize())
                    self.db.commit_person(person, transaction=self.trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        # FIXME: this probably needs to be removed, and bookmarks
        # should always be rebuilt on a commit_person via signals
        # self.parent.bookmarks.redraw()
        self.close()
        self.cb()
Exemple #58
0
    def _createmap(self, place_x):
        """
        Create all markers for each people's event in the database which has
        a lat/lon.
        """
        dbstate = self.dbstate
        self.cal = config.get('preferences.calendar-format-report')
        self.place_list = []
        self.places_found = []
        self.place_without_coordinates = []
        self.minlat = 0.0
        self.maxlat = 0.0
        self.minlon = 0.0
        self.maxlon = 0.0
        self.minyear = 9999
        self.maxyear = 0
        self.without = 0
        latitude = ""
        longitude = ""
        self.nbmarkers = 0
        self.nbplaces = 0
        self.message_layer.clear_messages()
        self.message_layer.clear_font_attributes()
        self.no_show_places_in_status_bar = False
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 1'23"
        # base "villes de france" : 38101 places :
        # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization
        # base "villes de france" : 38101 places :
        # gramps 3.4 python 2.7 ( draw_markers are estimated when we move the map)
        # 38101 places : createmap : 04'32"; create_markers : 0'04"; draw markers : N/A :: 0'03"
        # 65598 places : createmap : 10'03"; create_markers : 0'07"; draw markers : N/A :: 0'05"
        # gramps 3.5 python 2.7 new marker layer
        # 38101 places : createmap : 03'09"; create_markers : 0'01"; draw markers : 0'04"
        # 65598 places : createmap : 08'48"; create_markers : 0'01"; draw markers : 0'07"
        _LOG.debug("%s" %
                   time.strftime("start createmap : "
                                 "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.show_all:
            self.show_all = False
            try:
                places_handle = dbstate.db.get_place_handles()
            except:
                return
            progress = ProgressMeter(self.window_name,
                                     can_cancel=False,
                                     parent=self.uistate.window)
            length = len(places_handle)
            progress.set_pass(_('Selecting all places'), length)
            for place_hdl in places_handle:
                place = dbstate.db.get_place_from_handle(place_hdl)
                self._create_one_place(place)
                progress.step()
            progress.close()
        elif self.generic_filter:
            place_list = self.generic_filter.apply(dbstate.db)
            progress = ProgressMeter(self.window_name,
                                     can_cancel=False,
                                     parent=self.uistate.window)
            length = len(place_list)
            progress.set_pass(_('Selecting all places'), length)
            for place_handle in place_list:
                place = dbstate.db.get_place_from_handle(place_handle)
                self._create_one_place(place)
                progress.step()
            progress.close()
        elif place_x:
            place = dbstate.db.get_place_from_handle(place_x)
            self._create_one_place(place)
            if (place.get_latitude() != "" and place.get_longitude() != ""):
                self.osm.set_center_and_zoom(float(place.get_latitude()),
                                             float(place.get_longitude()),
                                             int(config.get("geography.zoom")))
        _LOG.debug(" stop createmap.")
        _LOG.debug("%s" % time.strftime("begin sort : "
                                        "%a %d %b %Y %H:%M:%S", time.gmtime()))
        self.sort = sorted(self.place_list, key=operator.itemgetter(0))
        _LOG.debug("%s" % time.strftime("  end sort : "
                                        "%a %d %b %Y %H:%M:%S", time.gmtime()))
        if self.nbmarkers > 500:  # performance issue. Is it the good value ?
            self.message_layer.add_message(
                _("The place name in the status bar is disabled."))
            self.no_show_places_in_status_bar = True
        if self.nbplaces >= self._config.get("geography.max_places"):
            self.message_layer.set_font_attributes(None, None, "red")
            self.message_layer.add_message(
                _("The maximum number of places is reached (%d)." %
                  self._config.get("geography.max_places")))
            self.message_layer.add_message(_("Some information are missing."))
            self.message_layer.add_message(
                _("Please, use filtering to reduce this number."))
            self.message_layer.add_message(
                _("You can modify this value in the geography option."))
            self.message_layer.add_message(
                _("In this case, it may take time to show all markers."))

        self._create_markers()