Beispiel #1
0
    def update(self, row):
        '''
        update the expander

        :param row: the row to get thevalues from
        '''
        syn_box = self.widgets.sp_synonyms_box
        # remove old labels
        syn_box.foreach(syn_box.remove)
        logger.debug(row.synonyms)
        from sqlalchemy.orm.session import object_session
        self.session = object_session(row)
        syn = self.session.query(SpeciesSynonym).filter(
            SpeciesSynonym.synonym_id == row.id).first()
        accepted = syn and syn.species
        logger.debug("species %s is synonym of %s and has synonyms %s" %
                     (row, accepted, row.synonyms))
        self.set_label(_("Synonyms"))  # reset default value
        on_label_clicked = lambda l, e, syn: select_in_search_results(syn)
        if accepted is not None:
            self.set_label(_("Accepted name"))
            # create clickable label that will select the synonym
            # in the search results
            box = gtk.EventBox()
            label = gtk.Label()
            label.set_alignment(0, .5)
            label.set_markup(Species.str(accepted, markup=True, authors=True))
            box.add(label)
            utils.make_label_clickable(label, on_label_clicked, accepted)
            syn_box.pack_start(box, expand=False, fill=False)
            self.show_all()
            self.set_sensitive(True)
            self.set_expanded(True)
        elif len(row.synonyms) == 0:
            self.set_sensitive(False)
            self.set_expanded(False)
        else:
            # remove all the children
            syn_box.foreach(syn_box.remove)
            for syn in row.synonyms:
                # create clickable label that will select the synonym
                # in the search results
                box = gtk.EventBox()
                label = gtk.Label()
                label.set_alignment(0, .5)
                label.set_markup(Species.str(syn, markup=True, authors=True))
                box.add(label)
                utils.make_label_clickable(label, on_label_clicked, syn)
                syn_box.pack_start(box, expand=False, fill=False)
            self.show_all()
            self.set_sensitive(True)
            # TODO: get expanded state from prefs
            self.set_expanded(True)
Beispiel #2
0
    def update(self, row):
        '''
        update the expander

        :param row: the row to get thevalues from
        '''
        syn_box = self.widgets.sp_synonyms_box
        # remove old labels
        syn_box.foreach(syn_box.remove)
        logger.debug(row.synonyms)
        from sqlalchemy.orm.session import object_session
        self.session = object_session(row)
        syn = self.session.query(SpeciesSynonym).filter(
            SpeciesSynonym.synonym_id == row.id).first()
        accepted = syn and syn.species
        logger.debug("species %s is synonym of %s and has synonyms %s" %
                     (row, accepted, row.synonyms))
        self.set_label(_("Synonyms"))  # reset default value
        on_label_clicked = lambda l, e, syn: select_in_search_results(syn)
        if accepted is not None:
            self.set_label(_("Accepted name"))
            # create clickable label that will select the synonym
            # in the search results
            box = gtk.EventBox()
            label = gtk.Label()
            label.set_alignment(0, .5)
            label.set_markup(Species.str(accepted, markup=True, authors=True))
            box.add(label)
            utils.make_label_clickable(label, on_label_clicked, accepted)
            syn_box.pack_start(box, expand=False, fill=False)
            self.show_all()
            self.set_sensitive(True)
            self.set_expanded(True)
        elif len(row.synonyms) == 0:
            self.set_sensitive(False)
            self.set_expanded(False)
        else:
            # remove all the children
            syn_box.foreach(syn_box.remove)
            for syn in row.synonyms:
                # create clickable label that will select the synonym
                # in the search results
                box = gtk.EventBox()
                label = gtk.Label()
                label.set_alignment(0, .5)
                label.set_markup(Species.str(syn, markup=True, authors=True))
                box.add(label)
                utils.make_label_clickable(label, on_label_clicked, syn)
                syn_box.pack_start(box, expand=False, fill=False)
            self.show_all()
            self.set_sensitive(True)
            # TODO: get expanded state from prefs
            self.set_expanded(True)
    def test_between_evaluate(self):
        'use BETWEEN value and value'
        Family = self.Family
        Genus = self.Genus
        from bauble.plugins.plants.species_model import Species
        from bauble.plugins.garden.accession import Accession
        #from bauble.plugins.garden.location import Location
        #from bauble.plugins.garden.plant import Plant
        family2 = Family(epithet=u'family2')
        g2 = Genus(family=family2, epithet=u'genus2')
        f3 = Family(epithet=u'fam3', aggregate=u'agg.')
        g3 = Genus(family=f3, epithet=u'Ixora')
        sp = Species(epithet=u"coccinea", genus=g3)
        ac = Accession(species=sp, code=u'1979.0001')
        self.session.add_all([family2, g2, f3, g3, sp, ac])
        self.session.commit()

        mapper_search = search.get_strategy('MapperSearch')
        self.assertTrue(isinstance(mapper_search, search.MapperSearch))

        s = 'accession where code between "1978" and "1980"'
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set([ac]))
        s = 'accession where code between "1980" and "1980"'
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set())
    def test_search_by_query22_underscore(self):
        """can use fields starting with an underscore"""

        import datetime
        Family = self.Family
        Genus = self.Genus
        from bauble.plugins.plants.species_model import Species
        from bauble.plugins.garden.accession import Accession
        from bauble.plugins.garden.location import Location
        from bauble.plugins.garden.plant import Plant
        family2 = Family(epithet=u'family2')
        g2 = Genus(family=family2, epithet=u'genus2')
        f3 = Family(epithet=u'fam3', aggregate=u'agg.')
        g3 = Genus(family=f3, epithet=u'Ixora')
        sp = Species(epithet=u"coccinea", genus=g3)
        ac = Accession(species=sp, code=u'1979.0001')
        lc = Location(name=u'loc1', code=u'loc1')
        pp = Plant(accession=ac, code=u'01', location=lc, quantity=1)
        pp._last_updated = datetime.datetime(2009, 2, 13)
        self.session.add_all([family2, g2, f3, g3, sp, ac, lc, pp])
        self.session.commit()

        mapper_search = search.get_strategy('MapperSearch')
        self.assertTrue(isinstance(mapper_search, search.MapperSearch))

        s = 'plant where _last_updated < |datetime|2000,1,1|'
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set())

        s = 'plant where _last_updated > |datetime|2000,1,1|'
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set([pp]))
Beispiel #5
0
    def __init__(self, model=None, parent=None):
        '''
        :param model: a species instance or None
        :param parent: the parent window or None
        '''
        if model is None:
            model = Species()
        super(SpeciesEditorMenuItem, self).__init__(model, parent)
        if not parent and bauble.gui:
            parent = bauble.gui.window
        self.parent = parent
        self._committed = []

        view = SpeciesEditorView(parent=self.parent)
        self.presenter = SpeciesEditorPresenter(self.model, view)

        ## I do not follow this: we have a MVP model, but also an extra
        ## 'Editor' thing and is it stealing functionality from either the
        ## view or the presenter?
        self.view = view

        # add quick response keys
        self.attach_response(view.get_window(), gtk.RESPONSE_OK, 'Return',
                             gtk.gdk.CONTROL_MASK)
        self.attach_response(view.get_window(), self.RESPONSE_OK_AND_ADD, 'k',
                             gtk.gdk.CONTROL_MASK)
        self.attach_response(view.get_window(), self.RESPONSE_NEXT, 'n',
                             gtk.gdk.CONTROL_MASK)

        # set default focus
        if self.model.genus is None:
            view.widgets.sp_genus_entry.grab_focus()
        else:
            view.widgets.sp_species_entry.grab_focus()
Beispiel #6
0
def add_species_callback(genera):
    session = db.Session()
    genus = session.merge(genera[0])
    from bauble.plugins.plants.species_editor import edit_species
    result = edit_species(model=Species(genus=genus)) is not None
    session.close()
    return result
    def refresh_fullname_label(self, widget=None):
        '''
        set the value of sp_fullname_label to either '--' if there
        is a problem or to the name of the string returned by Species.str
        '''
        logger.debug("SpeciesEditorPresenter:refresh_fullname_label %s"
                     % widget)
        if len(self.problems) > 0 or self.model.genus is None:
            self.view.set_label('sp_fullname_label', '--')
            return
        sp_str = Species.str(self.model, markup=True, authors=True)
        self.view.set_label('sp_fullname_label', sp_str)
        if self.model.genus is not None:
            genus = self.model.genus
            epithet = self.view.widget_get_value('sp_species_entry')
            omonym = self.session.query(
                Species).filter(
                Species.genus == genus,
                Species.sp == epithet
                ).first()
            logger.debug("looking for %s %s, found %s"
                         % (genus, epithet, omonym))
            if omonym in [None, self.model]:
                ## should not warn, so check warning and remove
                if self.omonym_box is not None:
                    self.view.remove_box(self.omonym_box)
                    self.omonym_box = None
            elif self.omonym_box is None:  # should warn, but not twice
                msg = _("This binomial name is already in your collection"
                        ", as %s.\n\n"
                        "Are you sure you want to insert it again?") % \
                    Species.str(omonym, authors=True)

                def on_response(button, response):
                    self.view.remove_box(self.omonym_box)
                    self.omonym_box = None
                    if response:
                        logger.warning('yes')
                    else:
                        self.view.widget_set_value('sp_species_entry', '')

                box = self.omonym_box = (
                    self.view.add_message_box(utils.MESSAGE_BOX_YESNO))
                box.message = msg
                box.on_response = on_response
                box.show()
                self.view.add_box(box)
 def setUp(self):
     super(BinomialSearchTests, self).setUp()
     db.engine.execute('delete from genus')
     db.engine.execute('delete from family')
     from bauble.plugins.plants.family import Family
     from bauble.plugins.plants.genus import Genus
     from bauble.plugins.plants.species import Species
     f1 = Family(epithet=u'family1', aggregate=u'agg.')
     g1 = Genus(family=f1, epithet=u'genus1')
     f2 = Family(epithet=u'family2')
     g2 = Genus(family=f2, epithet=u'genus2')
     f3 = Family(epithet=u'fam3', aggregate=u'agg.')
     g3 = Genus(family=f3, epithet=u'Ixora')
     sp = Species(epithet=u"coccinea", genus=g3)
     sp2 = Species(epithet=u"peruviana", genus=g3)
     sp3 = Species(epithet=u"chinensis", genus=g3)
     g4 = Genus(family=f3, epithet=u'Pachystachys')
     sp4 = Species(epithet=u'coccinea', genus=g4)
     self.session.add_all([f1, f2, g1, g2, f3, g3, sp, sp2, sp3, g4, sp4])
     self.session.commit()
     self.ixora, self.ic, self.pc = g3, sp, sp4
    def setUp(self):
        super(AggregatingFunctions, self).setUp()
        db.engine.execute('delete from genus')
        db.engine.execute('delete from family')
        db.engine.execute('delete from species')
        db.engine.execute('delete from accession')
        from bauble.plugins.plants import Family, Genus, Species
        f1 = Family(epithet=u'Rutaceae', aggregate=u'')
        g1 = Genus(family=f1, epithet=u'Citrus')
        sp1 = Species(epithet=u"medica", genus=g1)
        sp2 = Species(epithet=u"maxima", genus=g1)
        sp3 = Species(epithet=u"aurantium", genus=g1)

        f2 = Family(epithet=u'Sapotaceae')
        g2 = Genus(family=f2, epithet=u'Manilkara')
        sp4 = Species(epithet=u'zapota', genus=g2)
        sp5 = Species(epithet=u'zapotilla', genus=g2)
        g3 = Genus(family=f2, epithet=u'Pouteria')
        sp6 = Species(epithet=u'stipitata', genus=g3)

        f3 = Family(epithet=u'Musaceae')
        g4 = Genus(family=f3, epithet=u'Musa')
        self.session.add_all(
            [f1, f2, f3, g1, g2, g3, g4, sp1, sp2, sp3, sp4, sp5, sp6])
        self.session.commit()
    def test_cultivar_also_matched(self):
        mapper_search = search.get_strategy('MapperSearch')
        self.assertTrue(isinstance(mapper_search, search.MapperSearch))

        from bauble.plugins.plants.species import Species
        from bauble.plugins.plants.genus import Genus
        g3 = self.session.query(Genus).filter(Genus.epithet == u'Ixora').one()
        sp5 = Species(epithet=u"coccinea",
                      genus=g3,
                      infrasp1_rank=u'cv.',
                      infrasp1=u'Nora Grant')
        self.session.add_all([sp5])
        self.session.commit()
        s = 'Ixora coccinea'  # matches I.coccinea and Nora Grant
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set([self.ic, sp5]))
    def on_remove_button_clicked(self, button, data=None):
        """
        removes the currently selected synonym from the list of synonyms for
        this species
        """
        # TODO: maybe we should only ask 'are you sure' if the selected value
        # is an instance, this means it will be deleted from the database
        tree = self.view.widgets.sp_syn_treeview
        path, col = tree.get_cursor()
        tree_model = tree.get_model()
        value = tree_model[tree_model.get_iter(path)][0]
        s = Species.str(value.synonym, markup=True)
        msg = (
            "Are you sure you want to remove %s as a synonym to the "
            "current species?\n\n<i>Note: This will not remove the species "
            "%s from the database.</i>" % (s, s)
        )
        if not utils.yes_no_dialog(msg, parent=self.view.get_window()):
            return

        tree_model.remove(tree_model.get_iter(path))
        self.model.synonyms.remove(value.synonym)
        utils.delete_or_expunge(value)
        # TODO: ** important ** this doesn't respect any unique
        # contraints on the species for synonyms and allow a
        # species to have another species as a synonym multiple
        # times...see below

        # TODO: using session.flush here with an argument is
        # deprecated in SA 0.5 and will probably removed in SA
        # 0.6...but how do we only flush the one value..unless we
        # create a new session, merge it, commit that session,
        # close it and then refresh the same object in
        # self.session

        # make the change in synonym immediately available so that if
        # we try to add the same species again we don't break the
        # SpeciesSynonym UniqueConstraint

        # tmp_session = db.Session()
        # tmp_value = tmp.session.merge(value)
        # tmp.session.commit()
        # tmp.session.close()
        # self.session.refresh(value)
        # self.session.flush([value])
        self._dirty = True
        self.parent_ref().refresh_sensitivity()
Beispiel #12
0
    def on_remove_button_clicked(self, button, data=None):
        '''
        removes the currently selected synonym from the list of synonyms for
        this species
        '''
        # TODO: maybe we should only ask 'are you sure' if the selected value
        # is an instance, this means it will be deleted from the database
        tree = self.view.widgets.sp_syn_treeview
        path, col = tree.get_cursor()
        tree_model = tree.get_model()
        value = tree_model[tree_model.get_iter(path)][0]
        s = Species.str(value.synonym, markup=True)
        msg = 'Are you sure you want to remove %s as a synonym to the ' \
              'current species?\n\n<i>Note: This will not remove the species '\
              '%s from the database.</i>' % (s, s)
        if not utils.yes_no_dialog(msg, parent=self.view.get_window()):
            return

        tree_model.remove(tree_model.get_iter(path))
        self.model.synonyms.remove(value.synonym)
        utils.delete_or_expunge(value)
        # TODO: ** important ** this doesn't respect any unique
        # contraints on the species for synonyms and allow a
        # species to have another species as a synonym multiple
        # times...see below

        # TODO: using session.flush here with an argument is
        # deprecated in SA 0.5 and will probably removed in SA
        # 0.6...but how do we only flush the one value..unless we
        # create a new session, merge it, commit that session,
        # close it and then refresh the same object in
        # self.session

        # make the change in synonym immediately available so that if
        # we try to add the same species again we don't break the
        # SpeciesSynonym UniqueConstraint

        # tmp_session = db.Session()
        # tmp_value = tmp.session.merge(value)
        # tmp.session.commit()
        # tmp.session.close()
        # self.session.refresh(value)
        #self.session.flush([value])
        self._dirty = True
        self.parent_ref().refresh_sensitivity()
    def test_search_by_query_binomial(self):
        """can use genus_species binomial identification"""

        raise SkipTest("related to issue 192")
        Family = self.Family
        Genus = self.Genus
        from bauble.plugins.plants.species_model import Species
        family2 = Family(family=u'family2')
        g2 = Genus(family=family2, genus=u'genus2')
        f3 = Family(family=u'fam3', qualifier=u's. lat.')
        g3 = Genus(family=f3, genus=u'Ixora')
        sp = Species(sp=u"coccinea", genus=g3)
        self.session.add_all([family2, g2, f3, g3, sp])
        self.session.commit()

        mapper_search = search.get_strategy('MapperSearch')
        self.assertTrue(isinstance(mapper_search, search.MapperSearch))

        s = '"Ixora coccinea"'
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set([sp]))
    def test_search_by_query_vernacural(self):
        """can find species by vernacular name"""

        Family = self.Family
        Genus = self.Genus
        from bauble.plugins.plants.species_model import Species
        from bauble.plugins.plants.species_model import VernacularName
        family2 = Family(epithet=u'family2')
        g2 = Genus(family=family2, epithet=u'genus2')
        f3 = Family(epithet=u'fam3', aggregate=u'agg.')
        g3 = Genus(family=f3, epithet=u'Ixora')
        sp = Species(epithet=u"coccinea", genus=g3)
        vn = VernacularName(name=u"coral rojo", language=u"es", species=sp)
        self.session.add_all([family2, g2, f3, g3, sp, vn])
        self.session.commit()

        mapper_search = search.get_strategy('MapperSearch')
        self.assertTrue(isinstance(mapper_search, search.MapperSearch))

        s = "rojo"
        results = mapper_search.search(s, self.session)
        self.assertEqual(results, set([sp]))
                utils.message_details_dialog(msg, traceback.format_exc(),
                                             gtk.MESSAGE_ERROR)
                return False
        elif self.presenter.is_dirty() and utils.yes_no_dialog(not_ok_msg) \
                or not self.presenter.is_dirty():
            self.session.rollback()
            self.view.close_boxes()
            return True
        else:
            return False

        more_committed = None
        if response == self.RESPONSE_NEXT:
            self.presenter.cleanup()
            e = SpeciesEditorMenuItem(
                Species(genus=self.model.genus), self.parent)
            more_committed = e.start()
        elif response == self.RESPONSE_OK_AND_ADD:
            from bauble.plugins.garden.accession import (
                AccessionEditor, Accession)
            e = AccessionEditor(Accession(species=self.model),
                                parent=self.parent)
            more_committed = e.start()

        if more_committed is not None:
            if isinstance(more_committed, list):
                self._committed.extend(more_committed)
            else:
                self._committed.append(more_committed)

        self.view.close_boxes()
Beispiel #16
0
                logger.debug(traceback.format_exc())
                utils.message_details_dialog(msg, traceback.format_exc(),
                                             gtk.MESSAGE_ERROR)
                return False
        elif self.presenter.is_dirty() and utils.yes_no_dialog(not_ok_msg) \
                or not self.presenter.is_dirty():
            self.session.rollback()
            self.view.close_boxes()
            return True
        else:
            return False

        more_committed = None
        if response == self.RESPONSE_NEXT:
            self.presenter.cleanup()
            e = SpeciesEditorMenuItem(Species(genus=self.model.genus),
                                      self.parent)
            more_committed = e.start()
        elif response == self.RESPONSE_OK_AND_ADD:
            from bauble.plugins.garden.accession import (AccessionEditor,
                                                         Accession)
            e = AccessionEditor(Accession(species=self.model),
                                parent=self.parent)
            more_committed = e.start()

        if more_committed is not None:
            if isinstance(more_committed, list):
                self._committed.extend(more_committed)
            else:
                self._committed.append(more_committed)
Beispiel #17
0
            return True
        else:
            # we should never really even get here since we would have
            # to hit something besides "OK" and the above elif should
            # handle all the possible cases
            return False

        # respond to responses
        more_committed = None
        if response == self.RESPONSE_NEXT:
            self.presenter.cleanup()
            model = Genus(family=self.model.family)
            e = GenusEditor(model=model, parent=self.parent)
            more_committed = e.start()
        elif response == self.RESPONSE_OK_AND_ADD:
            sp = Species(genus=self.model)
            more_committed = edit_species(model=sp, parent=self.parent)

        if more_committed is not None:
            if isinstance(more_committed, list):
                self._committed.extend(more_committed)
            else:
                self._committed.append(more_committed)

        return True

    def start(self):
        if self.session.query(Family).count() == 0:
            msg = _('You must first add or import at least one Family into '
                    'the database before you can add plants.')
            utils.message_dialog(msg)