Esempio n. 1
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)
Esempio n. 2
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)
Esempio n. 3
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)
Esempio n. 4
0
class RelationTab(tool.Tool, ManagedWindow):
    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _("Relation and distances with root")
        self.dbstate = dbstate
        FilterClass = GenericFilterFactory('Person')
        self.path = '.'
        filter = FilterClass()

        tool.Tool.__init__(self, dbstate, options_class, name)
        if uistate:

            window = Gtk.Window()
            window.set_default_size(880, 600)

            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            window.add(box)

            # dirty work-around for Gtk.HeaderBar() and FolderChooser

            chooser = Gtk.FileChooserDialog(
                _("Folder Chooser"),
                parent=uistate.window,
                action=Gtk.FileChooserAction.SELECT_FOLDER,
                buttons=(_('_Cancel'), Gtk.ResponseType.CANCEL, _('_Select'),
                         Gtk.ResponseType.OK))
            chooser.set_tooltip_text(_("Please, select a folder"))
            status = chooser.run()
            if status == Gtk.ResponseType.OK:
                # work-around 'IsADirectoryError' with self()
                # TypeError: invalid file: gi.FunctionInfo()
                self.path = chooser.get_current_folder()
            chooser.destroy()

            ManagedWindow.__init__(self, uistate, [], self.__class__)
            self.titles = [
                (_('Rel_id'), 0, 40, INTEGER),  # would be INTEGER
                (_('Relation'), 1, 300, str),
                (_('Name'), 2, 200, str),
                (_('up'), 3, 35, INTEGER),
                (_('down'), 4, 35, INTEGER),
                (_('Common MRA'), 5, 40, INTEGER),
                (_('Rank'), 6, 40, INTEGER),
                (_('Period'), 7, 40, str),
            ]

            treeview = Gtk.TreeView()
            model = ListModel(treeview, self.titles)
            s = Gtk.ScrolledWindow()
            s.add(treeview)
            box.pack_start(s, True, True, 0)

            button = Gtk.Button(label=_("Save"))
            button.connect("clicked", self.button_clicked)
            box.pack_end(button, False, True, 0)

        self.stats_list = []

        # behavior can be different according to CPU and generation depth

        max_level = config.get('behavior.generation-depth')
        # compact and interlinked tree
        # single core 2.80 Ghz needs +/- 0.1 second per person
        if max_level >= 15:
            var = max_level * 0.01
        elif 10 <= max_level < 15:
            var = max_level * 0.02
        else:
            var = max_level * 0.025

        plist = self.dbstate.db.iter_person_handles()
        length = self.dbstate.db.get_number_of_people()
        default_person = self.dbstate.db.get_default_person()
        if uistate:
            self.progress = ProgressMeter(self.label,
                                          can_cancel=True,
                                          parent=window)
        else:
            self.progress = ProgressMeter(self.label)

        if default_person:  # rather designed for run via GUI...
            root_id = default_person.get_gramps_id()
            ancestors = rules.person.IsAncestorOf([str(root_id), True])
            descendants = rules.person.IsDescendantOf([str(root_id), True])
            related = rules.person.IsRelatedWith([str(root_id)])

            # filtering people can be useful on some large data set
            # counter on filtering pass was not efficient
            # Not the proper solution, but a lazy one providing expected message

            filter.add_rule(related)
            self.progress.set_pass(_('Please wait, filtering...'))
            filtered_list = filter.apply(self.dbstate.db, plist)

            relationship = get_relationship_calculator()
        else:  # TODO: provide selection widget for CLI and GUI
            WarningDialog(_("No default_person"))
            return

        count = 0
        filtered_people = len(filtered_list)
        self.progress.set_pass(_('Generating relation map...'),
                               filtered_people)
        if self.progress.get_cancelled():
            self.progress.close()
            return
        step_one = time.clock()  # init for counters
        for handle in filtered_list:
            nb = len(self.stats_list)
            count += 1
            self.progress.step()
            step_two = time.clock()
            start = 99
            if count > start:  # provide a basic interface for counters
                need = (step_two - step_one) / count
                wait = need * filtered_people
                remain = int(wait) - int(step_two - step_one)
                # sorry, lazy
                header = _("%d/%d \n %d/%d seconds \n %d/%d \n%f|\t%f" %
                           (count, filtered_people, remain, int(wait), nb,
                            length, float(need), float(var)))
                self.progress.set_header(header)
                if self.progress.get_cancelled():
                    self.progress.close()
                    return
            person = dbstate.db.get_person_from_handle(handle)

            timeout_one = time.clock()  # for delta and timeout estimations
            dist = relationship.get_relationship_distance_new(dbstate.db,
                                                              default_person,
                                                              person,
                                                              only_birth=True)
            timeout_two = time.clock()

            rank = dist[0][0]
            if rank == -1 or rank > max_level:  # not related and ignored people
                continue

            limit = timeout_two - timeout_one
            expect = (limit - var) / max_level
            if limit > var:
                n = name_displayer.display(person)
                _LOG.debug("Sorry! '{0}' needs {1} second, \
                            variation = '{2}'".format(n, limit, expect))
                continue
            else:
                _LOG.debug("variation = '{}'".format(
                    limit))  # delta, see above max_level 'wall' section
                rel = relationship.get_one_relationship(
                    dbstate.db, default_person, person)
                rel_a = dist[0][2]
                Ga = len(rel_a)
                rel_b = dist[0][4]
                Gb = len(rel_b)
                mra = 1

                # m: mother; f: father
                if Ga > 0:
                    for letter in rel_a:
                        if letter == 'm':
                            mra = mra * 2 + 1
                        if letter == 'f':
                            mra = mra * 2
                    # design: mra gender will be often female (m: mother)
                    if rel_a[-1] == "f" and Gb != 0:  # male gender, look at spouse
                        mra = mra + 1

                name = name_displayer.display(person)
                # pseudo privacy; sample for DNA stuff and mapping
                import hashlib
                no_name = hashlib.sha384(name.encode() +
                                         handle.encode()).hexdigest()
                _LOG.info(no_name)  # own internal password via handle

                kekule = number.get_number(Ga, Gb, rel_a, rel_b)

                # workaround - possible unique ID and common numbers
                uuid = str(uuid4())
                _LOG.info("Random UUID: {}".format(uuid))

                if kekule == "u":  # TODO: cousin(e)s need a key
                    kekule = 0
                if kekule == "nb":  # non-birth
                    kekule = -1
                try:
                    test = int(kekule)
                except:  # 1: related to mother; 0.x : no more girls lineage
                    kekule = 1

                period = get_timeperiod(self.dbstate.db, handle)

                # sometimes 'iterator' (generator) is more faster
                #handle_list = map(handle, filtered_list)
                iterator = (handle for handle in filtered_list)

                # experimentations; not used yet
                new_list = [int(kekule), int(Ga), int(Gb), int(mra), int(rank)]
                line = (iterator, array('b', new_list))

                self.stats_list.append(
                    (int(kekule), rel, name, int(Ga), int(Gb), int(mra),
                     int(rank), str(period)))
        self.progress.close()

        from itertools import groupby
        for key, items in groupby(self.stats_list, lambda x: x[0]):
            for subitem in items:
                _LOG.info(subitem)

        _LOG.debug("total: {}".format(nb))
        for entry in self.stats_list:
            if uistate:
                model.add(entry, entry[0])
            else:
                print(entry)
        if uistate:
            window.show()
            self.set_window(window, None, self.label)
            self.show()

    def save(self):
        """
        save action
        """
        doc = ODSTab(len(self.stats_list))
        doc.creator(self.db.get_researcher().get_name())
        name = self.dbstate.db.get_default_person().get_handle() + '.ods'
        if self.path != '.':
            name = os.path.join(self.path, name)
        try:
            import io
            io.open(name, "w", encoding='utf8')
        except PermissionError or IsADirectoryError:
            WarningDialog(_("You do not have write rights on this folder"))
            return

        spreadsheet = TableReport(name, doc)

        new_titles = []
        skip_columns = []
        index = 0
        for title in self.titles:
            if title == 'sort':
                skip_columns.append(index)
            else:
                new_titles.append(title)
            index += 1
        spreadsheet.initialize(len(new_titles))

        spreadsheet.write_table_head(new_titles)

        index = 0
        for top in self.stats_list:
            spreadsheet.set_row(index % 2)
            index += 1
            spreadsheet.write_table_data(top, skip_columns)

        spreadsheet.finalize()

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

    def button_clicked(self, button):
        self.save()
Esempio n. 5
0
class RelationTab(tool.Tool, ManagedWindow):

    def __init__(self, dbstate, user, options_class, name, callback=None):
        uistate = user.uistate
        self.label = _("Relation and distances with root")
        self.dbstate = dbstate
        FilterClass = GenericFilterFactory('Person')
        self.path = '.'
        filter = FilterClass()

        tool.Tool.__init__(self, dbstate, options_class, name)
        if uistate:

            window = Gtk.Window()
            window.set_default_size(880, 600)

            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            window.add(box)

            # dirty work-around for Gtk.HeaderBar() and FolderChooser

            chooser = Gtk.FileChooserDialog(_("Folder Chooser"),
                                            parent=uistate.window,
                                            action=Gtk.FileChooserAction.SELECT_FOLDER,
                                            buttons=(_('_Cancel'),
                                                     Gtk.ResponseType.CANCEL,
                                                     _('_Select'),
                                                     Gtk.ResponseType.OK))
            chooser.set_tooltip_text(_("Please, select a folder"))
            status = chooser.run()
            if status == Gtk.ResponseType.OK:
                # work-around 'IsADirectoryError' with self()
                # TypeError: invalid file: gi.FunctionInfo()
                self.path = chooser.get_current_folder()
            chooser.destroy()

            ManagedWindow.__init__(self, uistate, [],
                                   self.__class__)
            self.titles = [
                (_('Rel_id'), 0, 40, INTEGER), # would be INTEGER
                (_('Relation'), 1, 300, str),
                (_('Name'), 2, 200, str),
                (_('up'), 3, 35, INTEGER),
                (_('down'), 4, 35, INTEGER),
                (_('Common MRA'), 5, 40, INTEGER),
                (_('Rank'), 6, 40, INTEGER),
                (_('Period'), 7, 40, str),
                ]

            treeview = Gtk.TreeView()
            model = ListModel(treeview, self.titles)
            s = Gtk.ScrolledWindow()
            s.add(treeview)
            box.pack_start(s, True, True, 0)

            button = Gtk.Button(label=_("Save"))
            button.connect("clicked", self.button_clicked)
            box.pack_end(button, False, True, 0)

        self.stats_list = []

        # behavior can be different according to CPU and generation depth

        max_level = config.get('behavior.generation-depth')
        # compact and interlinked tree
        # single core 2.80 Ghz needs +/- 0.1 second per person
        if max_level >= 15:
            var = max_level * 0.01
        elif 10 <= max_level < 15:
            var = max_level * 0.02
        else:
            var = max_level * 0.025

        plist = self.dbstate.db.iter_person_handles()
        length = self.dbstate.db.get_number_of_people()
        default_person = self.dbstate.db.get_default_person()
        if uistate:
            self.progress = ProgressMeter(self.label, can_cancel=True,
                                          parent=window)
        else:
            self.progress = ProgressMeter(self.label)

        if default_person: # rather designed for run via GUI...
            root_id = default_person.get_gramps_id()
            ancestors = rules.person.IsAncestorOf([str(root_id), True])
            descendants = rules.person.IsDescendantOf([str(root_id), True])
            related = rules.person.IsRelatedWith([str(root_id)])

            # filtering people can be useful on some large data set
            # counter on filtering pass was not efficient
            # Not the proper solution, but a lazy one providing expected message

            filter.add_rule(related)
            self.progress.set_pass(_('Please wait, filtering...'))
            filtered_list = filter.apply(self.dbstate.db, plist)

            relationship = get_relationship_calculator()
        else: # TODO: provide selection widget for CLI and GUI
            WarningDialog(_("No default_person"))
            return

        count = 0
        filtered_people = len(filtered_list)
        self.progress.set_pass(_('Generating relation map...'), filtered_people)
        if self.progress.get_cancelled():
            self.progress.close()
            return
        step_one = time.clock() # init for counters
        for handle in filtered_list:
            nb = len(self.stats_list)
            count += 1
            self.progress.step()
            step_two = time.clock()
            start = 99
            if count > start: # provide a basic interface for counters
                need = (step_two - step_one) / count
                wait = need * filtered_people
                remain = int(wait) - int(step_two - step_one)
                # sorry, lazy
                header = _("%d/%d \n %d/%d seconds \n %d/%d \n%f|\t%f"
                           % (count, filtered_people, remain, int(wait),
                              nb, length, float(need), float(var))
                          )
                self.progress.set_header(header)
                if self.progress.get_cancelled():
                    self.progress.close()
                    return
            person = dbstate.db.get_person_from_handle(handle)

            timeout_one = time.clock() # for delta and timeout estimations
            dist = relationship.get_relationship_distance_new(
                dbstate.db, default_person, person, only_birth=True)
            timeout_two = time.clock()

            rank = dist[0][0]
            if rank == -1 or rank > max_level: # not related and ignored people
                continue

            limit = timeout_two - timeout_one
            expect = (limit - var) / max_level
            if limit > var:
                n = name_displayer.display(person)
                _LOG.debug("Sorry! '{0}' needs {1} second, \
                            variation = '{2}'".format(n,
                                                      limit,
                                                      expect
                                                     )
                          )
                continue
            else:
                _LOG.debug("variation = '{}'".format(limit)) # delta, see above max_level 'wall' section
                rel = relationship.get_one_relationship(
                    dbstate.db, default_person, person)
                rel_a = dist[0][2]
                Ga = len(rel_a)
                rel_b = dist[0][4]
                Gb = len(rel_b)
                mra = 1

                # m: mother; f: father
                if Ga > 0:
                    for letter in rel_a:
                        if letter == 'm':
                            mra = mra * 2 + 1
                        if letter == 'f':
                            mra = mra * 2
                    # design: mra gender will be often female (m: mother)
                    if rel_a[-1] == "f" and Gb != 0: # male gender, look at spouse
                        mra = mra + 1

                name = name_displayer.display(person)
                # pseudo privacy; sample for DNA stuff and mapping
                import hashlib
                no_name = hashlib.sha384(name.encode() + handle.encode()).hexdigest()
                _LOG.info(no_name) # own internal password via handle

                kekule = number.get_number(Ga, Gb, rel_a, rel_b)

                # workaround - possible unique ID and common numbers
                uuid = str(uuid4())
                _LOG.info("Random UUID: {}".format(uuid))

                if kekule == "u": # TODO: cousin(e)s need a key
                    kekule = 0
                if kekule == "nb": # non-birth
                    kekule = -1
                try:
                    test = int(kekule)
                except: # 1: related to mother; 0.x : no more girls lineage
                    kekule = 1

                period = get_timeperiod(self.dbstate.db, handle)

                # sometimes 'iterator' (generator) is more faster
                #handle_list = map(handle, filtered_list)
                iterator = (handle for handle in filtered_list)

                # experimentations; not used yet
                new_list=[int(kekule), int(Ga), int(Gb), int(mra), int(rank)]
                if max_level > 7:
                    line = (iterator, array('l', new_list))
                else:
                    line = (iterator, array('b', new_list))

                self.stats_list.append((int(kekule), rel, name, int(Ga),
                                        int(Gb), int(mra), int(rank), str(period)))
        self.progress.close()

        from itertools import groupby
        for key, items in groupby(self.stats_list, lambda x: x[0]):
            for subitem in items:
                _LOG.info(subitem)

        _LOG.debug("total: {}".format(nb))
        for entry in self.stats_list:
            if uistate:
                model.add(entry, entry[0])
            else:
                print(entry)
        if uistate:
            window.show()
            self.set_window(window, None, self.label)
            self.show()

    def save(self):
        """
        save action
        """
        doc = ODSTab(len(self.stats_list))
        doc.creator(self.db.get_researcher().get_name())
        name = self.dbstate.db.get_default_person().get_handle() + '.ods'
        if self.path != '.':
            name = os.path.join(self.path, name)
        try:
            import io
            io.open(name, "w", encoding='utf8')
        except PermissionError or IsADirectoryError:
            WarningDialog(_("You do not have write rights on this folder"))
            return

        spreadsheet = TableReport(name, doc)

        new_titles = []
        skip_columns = []
        index = 0
        for title in self.titles:
            if title == 'sort':
                skip_columns.append(index)
            else:
                new_titles.append(title)
            index += 1
        spreadsheet.initialize(len(new_titles))

        spreadsheet.write_table_head(new_titles)

        index = 0
        for top in self.stats_list:
            spreadsheet.set_row(index%2)
            index += 1
            spreadsheet.write_table_data(top, skip_columns)

        spreadsheet.finalize()

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

    def button_clicked(self, button):
        self.save()
Esempio n. 6
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 = 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-OK
                                      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 = top_dialog.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_cb)

        self.curr_fam = None
        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):
        """
        Find the descendants of a given person.
        """
        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_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)