def applyTagClicked(self, button):
        progress = None
        rows = self.treeSelection.count_selected_rows()
        tag_name = unicode(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'))
                #TRANS: no singular form needed, as rows is always > 1
                progress.set_pass(
                    ngettext("Setting tag for %d person",
                             "Setting tag for %d people", rows) % 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 #2
0
 def __get_addon_top(self, obj):
     """
     Toplevel method to get an addon.
     """
     from gui.utils import ProgressMeter
     pm = ProgressMeter(_("Installing Addon"), message_area=True)
     pm.set_pass(total=2, header=_("Reading gramps-project.org..."))
     pm.step()
     self.__get_addon(obj, callback=pm.append_message)
     pm.step()
     pm.message_area_ok.set_sensitive(True)
Exemple #3
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 #4
0
 def __get_all_addons(self, obj):
     """
     Get all addons from the wiki and install them.
     """
     import urllib
     from gui.utils import ProgressMeter
     pm = ProgressMeter(_("Install all Addons"),
                        _("Installing..."),
                        message_area=True)
     pm.set_pass(total=len(self.addon_model))
     for row in self.addon_model:
         pm.step()
         (help_name, name, ptype, image, desc, use, rating, contact,
          download, url) = row
         load_addon_file(url, callback=pm.append_message)
     self.uistate.viewmanager.do_reg_plugins(self.dbstate, self.uistate)
     pm.message_area_ok.set_sensitive(True)
     self.__rebuild_load_list()
     self.__rebuild_reg_list()
    def run_tool(self, cli=False):
        # Run tool and return results
        # These are English names, no conversion needed
        fromtype = self.options.handler.options_dict['fromtype']
        totype = self.options.handler.options_dict['totype']

        modified = 0

        with DbTxn(_('Change types'), self.db, batch=True) as self.trans:
            self.db.disable_signals()
            if not cli:
                progress = ProgressMeter(_('Analyzing Events'), '')
                progress.set_pass('', self.db.get_number_of_events())

            for event_handle in self.db.get_event_handles():
                event = self.db.get_event_from_handle(event_handle)
                if event.get_type().xml_str() == fromtype:
                    event.type.set_from_xml_str(totype)
                    modified += 1
                    self.db.commit_event(event, self.trans)
                if not cli:
                    progress.step()
            if not cli:
                progress.close()
        self.db.enable_signals()
        self.db.request_rebuild()

        if modified == 0:
            msg = _("No event record was modified.")
        else:
            msg = ngettext("%d event record was modified.",
                           "%d event records were modified.",
                           modified) % modified

        if cli:
            print "Done: ", msg
        return (bool(modified), msg)
Exemple #6
0
class ChangeNames(tool.BatchTool, ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        self.label = _('Capitalization changes')
        self.cb = callback

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

        tool.BatchTool.__init__(self, dbstate, uistate, 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 xrange(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 xrange(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"""
        GrampsDisplay.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 #7
0
class DisplayChart(ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, people_list, track):
        self.dbstate = dbstate
        self.uistate = uistate

        ManagedWindow.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
        window.show()
        self.set_window(window, self.topDialog.get_object('title'),
                        _('Event Comparison Results'))

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

        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"""
        GrampsDisplay.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'), '')
        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 = DateHandler.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.iteritems()],
                             by_value)

        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"),
                                  action=gtk.FILE_CHOOSER_ACTION_SAVE,
                                  buttons=(gtk.STOCK_CANCEL,
                                           gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE,
                                           gtk.RESPONSE_OK))

        f.set_current_folder(os.getcwd())
        status = f.run()
        f.hide()

        if status == gtk.RESPONSE_OK:
            name = Utils.get_unicode_path_from_file_chooser(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 #8
0
class MergeCitations(tool.BatchTool,ManagedWindow.ManagedWindow):
    
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.dbstate = dbstate
        self.set_window(gtk.Window(), gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, uistate, 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"""
        
        GrampsDisplay.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)
                key = citation.get_page()
                if fields <> IGNORE_DATE and fields <> IGNORE_BOTH:
                    key += "\n" + DateHandler.get_date(citation)
                if fields <> IGNORE_CONFIDENCE and fields <> IGNORE_BOTH:
                    key += "\n" + \
                        confidence[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"),
            ngettext("%(num)d citation merged",
            "%(num)d citations merged", num_merges) % {'num': num_merges})
        self.close(obj)
Exemple #9
0
class ReorderIds(tool.BatchTool):
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        tool.BatchTool.__init__(self, dbstate, uistate, 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(gen.lib.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(gen.lib.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(gen.lib.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(gen.lib.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(gen.lib.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(gen.lib.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(gen.lib.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(gen.lib.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(gen.lib.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 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 #10
0
class NotRelated(tool.ActivePersonTool, ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        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.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_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'))

        # 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.TREE_VIEW_COLUMN_AUTOSIZE)
        col2.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
        col3.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
        col4.set_sizing(gtk.TREE_VIEW_COLUMN_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.SELECTION_MULTIPLE)
        self.treeSelection.set_select_function(self.selectIsAllowed, full=True)
        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.SORT_ASCENDING)
            self.treeView.set_model(self.model)
            #            self.treeView.set_row_separator_func(self.iterIsSeparator)
            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):
        # 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 Errors.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 Errors.WindowActiveError:
                    pass

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

    def applyTagClicked(self, button):
        progress = None
        rows = self.treeSelection.count_selected_rows()
        tag_name = unicode(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'))
                #TRANS: no singular form needed, as rows is always > 1
                progress.set_pass(
                    ngettext("Setting tag for %d person",
                             "Setting tag for %d people", rows) % 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):

        #TRANS: No singular form is needed.
        self.progress.set_pass(
            ngettext("Finding relationships between %d person",
                     "Finding relationships between %d people",
                     self.numberOfPeopleInDatabase) %
            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 = ReportUtils.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(
                ngettext("Looking for %d person", "Looking for %d people",
                         self.numberOfUnrelatedPeople) %
                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(
            ngettext("Looking up the name of %d person",
                     "Looking up the names of %d people",
                     self.numberOfUnrelatedPeople) %
            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_root()
            # 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=locale.strxfrm)
        return ', '.join(tags)
Exemple #11
0
 def __refresh_addon_list(self, obj):
     """
     Reloads the addons from the wiki into the list.
     """
     import urllib
     from gui.utils import ProgressMeter
     URL = "%s%s" % (const.URL_WIKISTRING, const.WIKI_EXTRAPLUGINS_RAWDATA)
     try:
         fp = urllib.urlopen(URL)
     except:
         print "Error: cannot open %s" % URL
         return
     pm = ProgressMeter(_("Refreshing Addon List"))
     pm.set_pass(header=_("Reading gramps-project.org..."))
     state = "read"
     rows = []
     row = []
     lines = fp.readlines()
     pm.set_pass(total=len(lines),
                 header=_("Reading gramps-project.org..."))
     for line in lines:
         pm.step()
         if line.startswith("|-") or line.startswith("|}"):
             if row != []:
                 rows.append(row)
             state = "row"
             row = []
         elif state == "row":
             if line.startswith("|"):
                 row.append(line[1:].strip())
         else:
             state = "read"
     fp.close()
     rows.sort(key=lambda row: (row[1], row[0]))
     self.addon_model.clear()
     # clear the config list:
     config.get('plugin.addonplugins')[:] = []
     pm.set_pass(total=len(rows), header=_("Checking addon..."))
     for row in rows:
         pm.step()
         try:
             # from wiki:
             help_name, ptype, image, desc, use, rating, contact, download = row
         except:
             continue
         help_url = _("Unknown Help URL")
         if help_name.startswith("[[") and help_name.endswith("]]"):
             name = help_name[2:-2]
             if "|" in name:
                 help_url, name = name.split("|", 1)
         elif help_name.startswith("[") and help_name.endswith("]"):
             name = help_name[1:-1]
             if " " in name:
                 help_url, name = name.split(" ", 1)
         else:
             name = help_name
         url = _("Unknown URL")
         if download.startswith("[[") and download.endswith("]]"):
             # Not directly possible to get the URL:
             url = download[2:-2]
             if "|" in url:
                 url, text = url.split("|", 1)
             # need to get a page that says where it is:
             fp = urllib.urlopen(
                 "%s%s%s" % (const.URL_WIKISTRING, url,
                             "&action=edit&externaledit=true&mode=file"))
             for line in fp:
                 if line.startswith("URL="):
                     junk, url = line.split("=", 1)
                     break
             fp.close()
         elif download.startswith("[") and download.endswith("]"):
             url = download[1:-1]
             if " " in url:
                 url, text = url.split(" ", 1)
         if (url.endswith(".zip") or url.endswith(".ZIP")
                 or url.endswith(".tar.gz") or url.endswith(".tgz")):
             # Then this is ok:
             self.addon_model.append(row=[
                 help_name, name, ptype, image, desc, use, rating, contact,
                 download, url
             ])
             config.get('plugin.addonplugins').append([
                 help_name, name, ptype, image, desc, use, rating, contact,
                 download, url
             ])
     pm.close()
     config.save()
Exemple #12
0
class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
    titleid = 1
    nickid = 2
    pref1id = 3
    compid = 4

    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        self.label = _('Name and title extraction tool')
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(gtk.Window(), gtk.Label(), '')

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

        winprefix = gtk.Dialog(
            _("Default prefix and connector settings"), self.uistate.window,
            gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))

        winprefix.set_has_separator(False)
        winprefix.vbox.set_spacing(5)
        hboxpref = gtk.HBox()
        hboxpref.pack_start(gtk.Label(_('Prefixes to search for:')),
                            expand=False,
                            padding=5)
        self.prefixbox = gtk.Entry()
        self.prefixbox.set_text(', '.join(PREFIX_LIST))
        hboxpref.pack_start(self.prefixbox)
        winprefix.vbox.pack_start(hboxpref)
        hboxcon = gtk.HBox()
        hboxcon.pack_start(gtk.Label(_('Connectors splitting surnames:')),
                           expand=False,
                           padding=5)
        self.conbox = gtk.Entry()
        self.conbox.set_text(', '.join(CONNECTOR_LIST))
        hboxcon.pack_start(self.conbox)
        winprefix.vbox.pack_start(hboxcon)
        hboxconns = gtk.HBox()
        hboxconns.pack_start(gtk.Label(
            _('Connectors not splitting surnames:')),
                             expand=False,
                             padding=5)
        self.connsbox = gtk.Entry()
        self.connsbox.set_text(', '.join(CONNECTOR_LIST_NONSPLIT))
        hboxconns.pack_start(self.connsbox)
        winprefix.vbox.pack_start(hboxconns)
        winprefix.show_all()
        winprefix.resize(700, 100)

        response = winprefix.run()
        self.prefix_list = self.prefixbox.get_text().split(',')
        self.prefix_list = map(strip, self.prefix_list)
        self.prefixbox = None
        self.connector_list = self.conbox.get_text().split(',')
        self.connector_list = map(strip, self.connector_list)
        self.conbox = None
        self.connector_list_nonsplit = self.connsbox.get_text().split(',')
        self.connector_list_nonsplit = 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(_('Extracting Information from Names'),
                                      '')
        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 = map(strip, prefixes)
                    surnames = map(strip, surnames)
                    primaries = [False] * len(prefixes)
                    primaries[0] = True
                    origs = []
                    for ind in range(len(prefixes)):
                        origs.append(gen.lib.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 = gen.lib.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'),
                     _("No titles, nicknames or prefixes were found"))

    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(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"""
        GrampsDisplay.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(gen.lib.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()
class ExtractCity(tool.BatchTool, ManagedWindow.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, uistate, options_class, name, callback=None):
        self.label = _('Extract Place data')
        
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(gtk.Window(), gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, uistate, 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 = []

        for place in db.iter_places():
            descr = place.get_title()
            loc = place.get_main_location()
            self.progress.step()

            if loc.get_street() == loc.get_city() == \
               loc.get_state() == loc.get_postal_code() == "":

                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 QuestionDialog 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.get_title()

            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"""
        GrampsDisplay.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])
                (city, state, postal, country) = (row[2], row[3], row[4], row[5])

                if city:
                    place.get_main_location().set_city(city)
                if state:
                    place.get_main_location().set_state(state)
                if postal:
                    place.get_main_location().set_postal_code(postal)
                if country:
                    place.get_main_location().set_country(country)
                self.db.commit_place(place, self.trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        self.close()
Exemple #14
0
class User(gen.user.User):
    """
    This class provides a means to interact with the user via GTK.
    It implements the interface in gen.user.User()
    """
    def __init__(self):
        self.progress = None

    def begin_progress(self, title, message, steps):
        """
        Start showing a progress indicator to the user.
        
        @param title: the title of the progress meter
        @type title: str
        @param message: the message associated with the progress meter
        @type message: str
        @param steps: the total number of steps for the progress meter.
            a value of 0 indicates that the ending is unknown and the
            meter should just show activity.
        @type steps: int
        @returns: none
        """
        self.progress = ProgressMeter(title)
        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):
        """
        Advance the progress meter.
        """
        if self.progress:
            self.progress.step()

    def end_progress(self):
        """
        Stop showing the progress indicator to the user.
        """
        if self.progress:
            self.progress.close()
            self.progress = None

    def prompt(self, title, question):
        """
        Ask the user a question. The answer must be "yes" or "no".
        The user will be forced to answer the question before proceeding.
        
        @param title: the title of the question
        @type title: str
        @param question: the question
        @type question: str
        @returns: the user's answer to the question
        @rtype: bool
        """
        return False

    def warn(self, title, warning=""):
        """
        Warn the user.
        
        @param title: the title of the warning
        @type title: str
        @param warning: the warning
        @type warning: str
        @returns: none
        """
        WarningDialog(title, warning)

    def notify_error(self, title, error=""):
        """
        Notify the user of an error.
        
        @param title: the title of the error
        @type title: str
        @param error: the error message
        @type error: str
        @returns: none
        """
        ErrorDialog(title, error)