Ejemplo n.º 1
0
def _on_add_tag_activated(*args):
    # get the selection from the search view
    # TODO: would be better if we could set the sensitivity of the menu
    # item depending on if something was selected in the search view, this
    # means we need to add more hooks to the search view or include the
    # tag plugin into the search view
    view = bauble.gui.get_view()
    if isinstance(view, SearchView):
        values = view.get_selected_values()
        if len(values) == 0:
            msg = _('Nothing selected')
            utils.message_dialog(msg)
            return
        # right now we can only tag a single item at a time, if we did
        # the f-spot style quick tagging then it would be easier to handle
        # multiple tags at a time, we could do it we would just have to find
        # the common tags for each of the selected items and then select them
        # but grey them out so you can see that some of the items have that
        # tag but not all of them
        tagitem = TagItemGUI(values)
        tagitem.start()
        view.update_bottom_notebook()
    else:
        msg = _('In order to tag an item you must first search for '
                'something and select one of the results.')
        bauble.gui.show_message_box(msg)
Ejemplo n.º 2
0
    def add_meta(self, domain, cls, properties):
        """Add a domain to the search space

        an example of domain is a database table, where the properties would
        be the table columns to consider in the search.  continuing this
        example, a record is be selected if any of the fields matches the
        searched value.

        :param domain: a string, list or tuple of domains that will resolve
                       a search string to cls.  domain act as a shorthand to
                       the class name.
        :param cls: the class the domain will resolve to
        :param properties: a list of string names of the properties to
                           search by default
        """

        logger.debug('%s.add_meta(%s, %s, %s)' %
                     (self, domain, cls, properties))

        check(isinstance(properties, list),
              _('MapperSearch.add_meta(): '
                'default_columns argument must be list'))
        check(len(properties) > 0,
              _('MapperSearch.add_meta(): '
                'default_columns argument cannot be empty'))
        if isinstance(domain, (list, tuple)):
            self._domains[domain[0]] = cls, properties
            for d in domain[1:]:
                self._shorthand[d] = domain[0]
        else:
            self._domains[domain] = cls, properties
        self._properties[cls] = properties
Ejemplo n.º 3
0
    def conservation(self):
        '''the IUCN conservation status of this taxon, or DD

        one of: EX, RE, CR, EN, VU, NT, LC, DD
        not enforced by the software in v1.0.x
        '''

        {
            'EX': _('Extinct (EX)'),
            'EW': _('Extinct Wild (EW)'),
            'RE': _('Regionally Extinct (RE)'),
            'CR': _('Critically Endangered (CR)'),
            'EN': _('Endangered (EN)'),
            'VU': _('Vulnerable (VU)'),
            'NT': _('Near Threatened (NT)'),
            'LV': _('Least Concern (LC)'),
            'DD': _('Data Deficient (DD)'),
            'NE': _('Not Evaluated (NE)')
        }

        notes = [
            i.note for i in self.notes
            if i.category and i.category.upper() == u'IUCN'
        ]
        return (notes + ['DD'])[0]
Ejemplo n.º 4
0
    def start(self, filename=None, plants=None):
        if filename is None:  # no filename, ask the user
            d = gtk.FileChooserDialog(_("Choose a file to export to..."), None,
                                      gtk.FILE_CHOOSER_ACTION_SAVE,
                                      (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
                                       gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
            response = d.run()
            filename = d.get_filename()
            d.destroy()
            if response != gtk.RESPONSE_ACCEPT or filename is None:
                return

        if plants:
            nplants = len(plants)
        else:
            nplants = db.Session().query(Plant).count()

        if nplants > 3000:
            msg = _('You are exporting %(nplants)s plants to ABCD format.  '
                    'Exporting this many plants may take several minutes.  '
                    '\n\n<i>Would you like to continue?</i>') \
                % ({'nplants': nplants})
            if not utils.yes_no_dialog(msg):
                return
        self.run(filename, plants)
Ejemplo n.º 5
0
    def __init__(self, *args, **kwargs):
        super(SchemaBrowser, self).__init__(*args, **kwargs)
        self.props.spacing = 10
        # WARNING: this is a hack from MapperSearch
        self.domain_map = {}
        self.domain_map = MapperSearch.get_domain_classes().copy()

        frame = gtk.Frame(_("Search Domain"))
        self.pack_start(frame, expand=False, fill=False)
        self.table_combo = gtk.combo_box_new_text()
        frame.add(self.table_combo)
        for key in sorted(self.domain_map.keys()):
            self.table_combo.append_text(key)

        self.table_combo.connect('changed', self.on_table_combo_changed)

        self.prop_tree = gtk.TreeView()
        self.prop_tree.set_headers_visible(False)
        cell = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Property"), cell)
        self.prop_tree.append_column(column)
        column.add_attribute(cell, 'text', 0)

        self.prop_tree.connect('test_expand_row', self.on_row_expanded)

        frame = gtk.Frame(_('Domain Properties'))
        sw = gtk.ScrolledWindow()
        sw.add(self.prop_tree)
        frame.add(sw)
        self.pack_start(frame, expand=True, fill=True)
Ejemplo n.º 6
0
def remove_callback(values):
    """
    The callback function to remove a species from the species context menu.
    """
    from bauble.plugins.garden.accession import Accession

    session = db.Session()
    species = values[0]
    if isinstance(species, VernacularName):
        species = species.species
    nacc = session.query(Accession).filter_by(species_id=species.id).count()
    safe_str = utils.xml_safe(str(species))
    if nacc > 0:
        msg = _(
            "The species <i>%(species)s</i> has %(num_accessions)s " "accessions.  Are you sure you want remove it?"
        ) % dict(species=safe_str, num_accessions=nacc)
    else:
        msg = _("Are you sure you want to remove the species <i>%s</i>?") % safe_str
    if not utils.yes_no_dialog(msg):
        return
    try:
        obj = session.query(Species).get(species.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _("Could not delete.\n\n%s") % utils.xml_safe(e)
        utils.message_details_dialog(msg, traceback.format_exc(), type=gtk.MESSAGE_ERROR)
Ejemplo n.º 7
0
def _reset_tags_menu():
    tags_menu = gtk.Menu()
    add_tag_menu_item = gtk.MenuItem(_('Tag Selection'))
    add_tag_menu_item.connect('activate', _on_add_tag_activated)
    accel_group = gtk.AccelGroup()
    bauble.gui.window.add_accel_group(accel_group)
    add_tag_menu_item.add_accelerator('activate', accel_group, ord('T'),
                                      gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
    tags_menu.append(add_tag_menu_item)

    #manage_tag_item = gtk.MenuItem('Manage Tags')
    #tags_menu.append(manage_tag_item)
    tags_menu.append(gtk.SeparatorMenuItem())
    session = db.Session()
    query = session.query(Tag)
    try:
        for tag in query:
            item = gtk.MenuItem(tag.tag, use_underline=False)
            item.connect("activate", _tag_menu_item_activated, tag.tag)
            tags_menu.append(item)
    except Exception:
        logger.debug(traceback.format_exc())
        msg = _('Could not create the tags menus')
        utils.message_details_dialog(msg, traceback.format_exc(),
                                     gtk.MESSAGE_ERROR)

    global _tags_menu_item
    if _tags_menu_item is None:
        _tags_menu_item = bauble.gui.add_menu(_("Tags"), tags_menu)
    else:
        _tags_menu_item.remove_submenu()
        _tags_menu_item.set_submenu(tags_menu)
        _tags_menu_item.show_all()
    session.close()
Ejemplo n.º 8
0
def remove_callback(families):
    """
    The callback function to remove a family from the family context menu.
    """
    family = families[0]
    from bauble.plugins.plants.genus import Genus
    session = db.Session()
    ngen = session.query(Genus).filter_by(family_id=family.id).count()
    safe_str = utils.xml_safe(str(family))
    if ngen > 0:
        msg = _('The family <i>%(family)s</i> has %(num_genera)s genera.  Are '
                'you sure you want to remove it?') % dict(family=safe_str,
                                                          num_genera=ngen)
    else:
        msg = _("Are you sure you want to remove the family <i>%s</i>?") \
            % safe_str
    if not utils.yes_no_dialog(msg):
        return
    try:
        obj = session.query(Family).get(family.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _('Could not delete.\n\n%s') % utils.xml_safe(e)
        utils.message_details_dialog(msg,
                                     traceback.format_exc(),
                                     type=gtk.MESSAGE_ERROR)
Ejemplo n.º 9
0
 def format(objs, **kwargs):
     template_filename = kwargs["template"]
     use_private = kwargs.get("private", True)
     if not template_filename:
         msg = _("Please select a template.")
         utils.message_dialog(msg, gtk.MESSAGE_WARNING)
         return False
     template = Template(filename=template_filename, input_encoding="utf-8", output_encoding="utf-8")
     session = db.Session()
     values = map(session.merge, objs)
     report = template.render(values=values)
     session.close()
     # assume the template is the same file type as the output file
     head, ext = os.path.splitext(template_filename)
     fd, filename = tempfile.mkstemp(suffix=ext)
     os.write(fd, report)
     os.close(fd)
     try:
         desktop.open(filename)
     except OSError:
         utils.message_dialog(
             _("Could not open the report with the " "default program. You can open the " "file manually at %s")
             % filename
         )
     return report
Ejemplo n.º 10
0
 def handle_response(self, response):
     """
     @return: return True if the editor is ready to be closed, False if
     we want to keep editing, if any changes are committed they are stored
     in self._committed
     """
     # TODO: need to do a __cleanup_model before the commit to do things
     # like remove the insfraspecific information that's attached to the
     # model if the infraspecific rank is None
     not_ok_msg = 'Are you sure you want to lose your changes?'
     if response == gtk.RESPONSE_OK or response in self.ok_responses:
         try:
             if self.presenter.is_dirty():
                 self.commit_changes()
                 self._committed.append(self.model)
         except DBAPIError, e:
             msg = _('Error committing changes.\n\n%s') % \
                 utils.xml_safe(e.orig)
             logger.debug(traceback.format_exc())
             utils.message_details_dialog(msg, str(e), gtk.MESSAGE_ERROR)
             return False
         except Exception, e:
             msg = _('Unknown error when committing changes. See the '
                     'details for more information.\n\n%s') % \
                 utils.xml_safe(e)
             logger.debug(traceback.format_exc())
             utils.message_details_dialog(msg, traceback.format_exc(),
                                          gtk.MESSAGE_ERROR)
             return False
Ejemplo n.º 11
0
    def run(self, filenames, metadata, force=False):
        '''
        A generator method for importing filenames into the database.
        This method periodically yields control so that the GUI can
        update.

        :param filenames:
        :param metadata:
        :param force: default=False
        '''
        transaction = None
        connection = None
        self.__error_exc = BaubleError(_('Unknown Error.'))

        try:
            # user a contextual connect in case whoever called this
            # method called it inside a transaction then we can pick
            # up the parent connection and the transaction
            connection = metadata.bind.connect()
            transaction = connection.begin()
        except Exception, e:
            msg = _('Error connecting to database.\n\n%s') % \
                utils.xml_safe(e)
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            return
Ejemplo n.º 12
0
 def handle_response(self, response, commit=True):
     '''
     handle the response from self.presenter.start() in self.start()
     '''
     not_ok_msg = 'Are you sure you want to lose your changes?'
     self._return = None
     self.clean_model()
     if response == gtk.RESPONSE_OK or response in self.ok_responses:
         try:
             self._return = self.model
             if self.presenter.is_dirty() and commit:
                 self.commit_changes()
         except DBAPIError, e:
             msg = _('Error committing changes.\n\n%s') % \
                 utils.xml_safe(unicode(e.orig))
             utils.message_details_dialog(msg, str(e), gtk.MESSAGE_ERROR)
             self.session.rollback()
             return False
         except Exception, e:
             msg = _('Unknown error when committing changes. See the '
                     'details for more information.\n\n%s') %\
                 utils.xml_safe(e)
             logger.debug(traceback.format_exc())
             utils.message_details_dialog(msg, traceback.format_exc(),
                                          gtk.MESSAGE_ERROR)
             self.session.rollback()
             return False
Ejemplo n.º 13
0
    def __export_task(self, path):
        #        if not os.path.exists(path):
        #            raise ValueError("CSVExporter: path does not exist.\n" + path)
        filename_template = os.path.join(path, "%s.txt")
        #        timeout = tasklet.WaitForTimeout(12)
        steps_so_far = 0
        ntables = 0
        for table in db.metadata.sorted_tables:
            ntables += 1
            filename = filename_template % table.name
            if os.path.exists(filename):
                msg = _(
                    "Export file <b>%(filename)s</b> for "
                    "<b>%(table)s</b> table already exists.\n\n<i>Would "
                    "you like to continue?</i>"
                ) % {"filename": filename, "table": table.name}
                if utils.yes_no_dialog(msg):
                    return

        def replace(s):
            if isinstance(s, (str, unicode)):
                s.replace("\n", "\\n")
            return s

        def write_csv(filename, rows):
            f = open(filename, "wb")
            writer = UnicodeWriter(f, quotechar=QUOTE_CHAR, quoting=QUOTE_STYLE)
            writer.writerows(rows)
            f.close()

        update_every = 30
        for table in db.metadata.sorted_tables:
            filename = filename_template % table.name
            steps_so_far += 1
            fraction = float(steps_so_far) / float(ntables)
            pb_set_fraction(fraction)
            msg = _("exporting %(table)s table to %(filename)s") % {"table": table.name, "filename": filename}
            bauble.task.set_message(msg)
            logger.info("exporting %s" % table.name)

            # get the data
            results = table.select().execute().fetchall()

            # create empty files with only the column names
            if len(results) == 0:
                write_csv(filename, [table.c.keys()])
                yield
                continue

            rows = []
            rows.append(table.c.keys())  # append col names
            ctr = 0
            for row in results:
                values = map(replace, row.values())
                rows.append(values)
                if ctr == update_every:
                    yield
                    ctr = 0
                ctr += 1
            write_csv(filename, rows)
Ejemplo n.º 14
0
    def start(self):
        '''
        '''
        # get the select results from the search view
        from bauble.view import SearchView
        view = bauble.gui.get_view()
        if not isinstance(view, SearchView):
            utils.message_dialog(_('Search for something first.'))
            return

        model = view.results_view.get_model()
        if model is None:
            utils.message_dialog(_('Search for something first.'))
            return

        bauble.gui.set_busy(True)
        ok = False
        try:
            while True:
                dialog = ReportToolDialog()
                formatter, settings = dialog.start()
                if formatter is None:
                    break
                ok = formatter.format([row[0] for row in model], **settings)
                if ok:
                    break
        except AssertionError, e:
            logger.debug(e)
            logger.debug(traceback.format_exc())
            parent = None
            if hasattr(self, 'view') and hasattr(self.view, 'dialog'):
                parent = self.view.dialog

            utils.message_details_dialog(str(e), traceback.format_exc(),
                                         gtk.MESSAGE_ERROR, parent=parent)
 def handle_response(self, response, commit=True):
     '''
     handle the response from self.presenter.start() in self.start()
     '''
     not_ok_msg = 'Are you sure you want to lose your changes?'
     self._return = None
     self.clean_model()
     if response == gtk.RESPONSE_OK or response in self.ok_responses:
         try:
             self._return = self.model
             if self.presenter.dirty() and commit:
                 self.commit_changes()
         except DBAPIError, e:
             msg = _('Error committing changes.\n\n%s') % \
                 utils.xml_safe(unicode(e.orig))
             utils.message_details_dialog(msg, str(e), gtk.MESSAGE_ERROR)
             self.session.rollback()
             return False
         except Exception, e:
             msg = _('Unknown error when committing changes. See the '
                     'details for more information.\n\n%s') %\
                 utils.xml_safe(e)
             logger.debug(traceback.format_exc())
             utils.message_details_dialog(msg, traceback.format_exc(),
                                          gtk.MESSAGE_ERROR)
             self.session.rollback()
             return False
Ejemplo n.º 16
0
    def start(self):
        '''
        '''
        # get the select results from the search view
        from bauble.view import SearchView
        view = bauble.gui.get_view()
        if not isinstance(view, SearchView):
            utils.message_dialog(_('Search for something first.'))
            return

        model = view.results_view.get_model()
        if model is None:
            utils.message_dialog(_('Search for something first.'))
            return

        bauble.gui.set_busy(True)
        ok = False
        try:
            while True:
                dialog = ReportToolDialog()
                formatter, settings = dialog.start()
                if formatter is None:
                    break
                ok = formatter.format([row[0] for row in model], **settings)
                if ok:
                    break
        except AssertionError, e:
            logger.debug(e)
            logger.debug(traceback.format_exc())
            parent = None
            if hasattr(self, 'view') and hasattr(self.view, 'dialog'):
                parent = self.view.dialog

            utils.message_details_dialog(str(e), traceback.format_exc(),
                                         gtk.MESSAGE_ERROR, parent=parent)
Ejemplo n.º 17
0
def remove_callback(values):
    """
    The callback function to remove a species from the species context menu.
    """
    from bauble.plugins.garden.accession import Accession
    session = db.Session()
    species = values[0]
    if isinstance(species, VernacularName):
        species = species.species
    nacc = session.query(Accession).filter_by(species_id=species.id).count()
    safe_str = utils.xml_safe(str(species))
    if nacc > 0:
        msg = _('The species <i>%(species)s</i> has %(num_accessions)s '
                'accessions.  Are you sure you want remove it?') \
            % dict(species=safe_str, num_accessions=nacc)
    else:
        msg = _("Are you sure you want to remove the species <i>%s</i>?") \
            % safe_str
    if not utils.yes_no_dialog(msg):
        return
    try:
        obj = session.query(Species).get(species.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _('Could not delete.\n\n%s') % utils.xml_safe(e)
        utils.message_details_dialog(msg,
                                     traceback.format_exc(),
                                     type=gtk.MESSAGE_ERROR)
Ejemplo n.º 18
0
def remove_callback(genera):
    """
    The callback function to remove a genus from the genus context menu.
    """
    genus = genera[0]
    from bauble.plugins.plants.species_model import Species
    session = db.Session()
    nsp = session.query(Species).filter_by(genus_id=genus.id).count()
    safe_str = utils.xml_safe(str(genus))
    if nsp > 0:
        msg = (_('The genus <i>%(genus)s</i> has %(num_species)s species.  '
                 'Are you sure you want to remove it?') %
               dict(genus=safe_str, num_species=nsp))
    else:
        msg = (_("Are you sure you want to remove the genus <i>%s</i>?") %
               safe_str)
    if not utils.yes_no_dialog(msg):
        return
    try:
        obj = session.query(Genus).get(genus.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _('Could not delete.\n\n%s') % utils.xml_safe(e)
        utils.message_details_dialog(msg,
                                     traceback.format_exc(),
                                     type=gtk.MESSAGE_ERROR)
Ejemplo n.º 19
0
    def add_meta(self, domain, cls, properties):
        """Add a domain to the search space

        an example of domain is a database table, where the properties would
        be the table columns to consider in the search.  continuing this
        example, a record is be selected if any of the fields matches the
        searched value.

        :param domain: a string, list or tuple of domains that will resolve
                       a search string to cls.  domain act as a shorthand to
                       the class name.
        :param cls: the class the domain will resolve to
        :param properties: a list of string names of the properties to
                           search by default
        """

        logger.debug('%s.add_meta(%s, %s, %s)' %
                     (self, domain, cls, properties))

        check(
            isinstance(properties, list),
            _('MapperSearch.add_meta(): '
              'default_columns argument must be list'))
        check(
            len(properties) > 0,
            _('MapperSearch.add_meta(): '
              'default_columns argument cannot be empty'))
        if isinstance(domain, (list, tuple)):
            self._domains[domain[0]] = cls, properties
            for d in domain[1:]:
                self._shorthand[d] = domain[0]
        else:
            self._domains[domain] = cls, properties
        self._properties[cls] = properties
Ejemplo n.º 20
0
 def __init__(self, values, empty_to_none=False, strict=True,
              translations={}, **kwargs):
     """
     : param values: A list of valid values for column.
     :param empty_to_none: Treat the empty string '' as None.  None
     must be in the values list in order to set empty_to_none=True.
     :param strict:
     :param translations: A dictionary of values->translation
     """
     # create the translations from the values and set those from
     # the translations argument, this way if some translations are
     # missing then the translation will be the same as value
     self.translations = dict((v, v) for v in values)
     for key, value in translations.iteritems():
         self.translations[key] = value
     if values is None or len(values) is 0:
         raise EnumError(_('Enum requires a list of values'))
     if empty_to_none and None not in values:
         raise EnumError(_('You have configured empty_to_none=True but '
                           'None is not in the values lists'))
     self.values = values[:]
     self.strict = strict
     self.empty_to_none = empty_to_none
     # the length of the string/unicode column should be the
     # longest string in values
     size = max([len(v) for v in values if v is not None])
     super(Enum, self).__init__(size, **kwargs)
Ejemplo n.º 21
0
 def format(objs, **kwargs):
     template_filename = kwargs['template']
     use_private = kwargs.get('private', True)
     if not template_filename:
         msg = _('Please select a template.')
         utils.message_dialog(msg, gtk.MESSAGE_WARNING)
         return False
     template = Template(filename=template_filename,
                         input_encoding='utf-8',
                         output_encoding='utf-8')
     session = db.Session()
     values = map(session.merge, objs)
     report = template.render(values=values)
     session.close()
     # assume the template is the same file type as the output file
     head, ext = os.path.splitext(template_filename)
     fd, filename = tempfile.mkstemp(suffix=ext)
     os.write(fd, report)
     os.close(fd)
     try:
         desktop.open(filename)
     except OSError:
         utils.message_dialog(
             _('Could not open the report with the '
               'default program. You can open the '
               'file manually at %s') % filename)
     return report
Ejemplo n.º 22
0
def remove_callback(families):
    """
    The callback function to remove a family from the family context menu.
    """
    family = families[0]
    from bauble.plugins.plants.genus import Genus
    session = db.Session()
    ngen = session.query(Genus).filter_by(family_id=family.id).count()
    safe_str = utils.xml_safe(str(family))
    if ngen > 0:
        msg = _('The family <i>%(family)s</i> has %(num_genera)s genera.  Are '
                'you sure you want to remove it?') % dict(family=safe_str,
                                                          num_genera=ngen)
    else:
        msg = _("Are you sure you want to remove the family <i>%s</i>?") \
            % safe_str
    if not utils.yes_no_dialog(msg):
        return
    try:
        obj = session.query(Family).get(family.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _('Could not delete.\n\n%s') % utils.xml_safe(e)
        utils.message_details_dialog(msg, traceback.format_exc(),
                                     type=gtk.MESSAGE_ERROR)
Ejemplo n.º 23
0
 def handle_response(self, response):
     """
     @return: return True if the editor is ready to be closed, False if
     we want to keep editing, if any changes are committed they are stored
     in self._committed
     """
     # TODO: need to do a __cleanup_model before the commit to do things
     # like remove the insfraspecific information that's attached to the
     # model if the infraspecific rank is None
     not_ok_msg = 'Are you sure you want to lose your changes?'
     if response == gtk.RESPONSE_OK or response in self.ok_responses:
         try:
             if self.presenter.is_dirty():
                 self.commit_changes()
                 self._committed.append(self.model)
         except DBAPIError, e:
             msg = _('Error committing changes.\n\n%s') % \
                 utils.xml_safe(e.orig)
             logger.debug(traceback.format_exc())
             utils.message_details_dialog(msg, str(e), gtk.MESSAGE_ERROR)
             return False
         except Exception, e:
             msg = _('Unknown error when committing changes. See the '
                     'details for more information.\n\n%s') % \
                 utils.xml_safe(e)
             logger.debug(traceback.format_exc())
             utils.message_details_dialog(msg, traceback.format_exc(),
                                          gtk.MESSAGE_ERROR)
             return False
Ejemplo n.º 24
0
def _reset_tags_menu():
    tags_menu = gtk.Menu()
    add_tag_menu_item = gtk.MenuItem(_('Tag Selection'))
    add_tag_menu_item.connect('activate', _on_add_tag_activated)
    accel_group = gtk.AccelGroup()
    bauble.gui.window.add_accel_group(accel_group)
    add_tag_menu_item.add_accelerator('activate', accel_group, ord('T'),
                                      gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
    tags_menu.append(add_tag_menu_item)

    #manage_tag_item = gtk.MenuItem('Manage Tags')
    #tags_menu.append(manage_tag_item)
    tags_menu.append(gtk.SeparatorMenuItem())
    session = db.Session()
    query = session.query(Tag)
    try:
        for tag in query:
            item = gtk.MenuItem(tag.tag, use_underline=False)
            item.connect("activate", _tag_menu_item_activated, tag.tag)
            tags_menu.append(item)
    except Exception:
        logger.debug(traceback.format_exc())
        msg = _('Could not create the tags menus')
        utils.message_details_dialog(msg, traceback.format_exc(),
                                     gtk.MESSAGE_ERROR)

    global _tags_menu_item
    if _tags_menu_item is None:
        _tags_menu_item = bauble.gui.add_menu(_("Tags"), tags_menu)
    else:
        _tags_menu_item.remove_submenu()
        _tags_menu_item.set_submenu(tags_menu)
        _tags_menu_item.show_all()
    session.close()
Ejemplo n.º 25
0
    def start(self, filename=None, plants=None):
        if filename is None:  # no filename, ask the user
            d = gtk.FileChooserDialog(_("Choose a file to export to..."), None,
                                      gtk.FILE_CHOOSER_ACTION_SAVE,
                                      (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
                                       gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
            response = d.run()
            filename = d.get_filename()
            d.destroy()
            if response != gtk.RESPONSE_ACCEPT or filename is None:
                return

        if plants:
            nplants = len(plants)
        else:
            nplants = db.Session().query(Plant).count()

        if nplants > 3000:
            msg = _('You are exporting %(nplants)s plants to ABCD format.  '
                    'Exporting this many plants may take several minutes.  '
                    '\n\n<i>Would you like to continue?</i>') \
                % ({'nplants': nplants})
            if not utils.yes_no_dialog(msg):
                return
        self.run(filename, plants)
Ejemplo n.º 26
0
class ABCDExportTool(pluginmgr.Tool):
    category = _("Export")
    label = _("ABCD")

    @classmethod
    def start(cls):
        ABCDExporter().start()
Ejemplo n.º 27
0
    def run(self, filenames, metadata, force=False):
        '''
        A generator method for importing filenames into the database.
        This method periodically yields control so that the GUI can
        update.

        :param filenames:
        :param metadata:
        :param force: default=False
        '''
        transaction = None
        connection = None
        self.__error_exc = BaubleError(_('Unknown Error.'))

        try:
            # user a contextual connect in case whoever called this
            # method called it inside a transaction then we can pick
            # up the parent connection and the transaction
            connection = metadata.bind.connect()
            transaction = connection.begin()
        except Exception, e:
            msg = _('Error connecting to database.\n\n%s') % \
                utils.xml_safe(e)
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            return
Ejemplo n.º 28
0
def _on_add_tag_activated(*args):
    # get the selection from the search view
    # TODO: would be better if we could set the sensitivity of the menu
    # item depending on if something was selected in the search view, this
    # means we need to add more hooks to the search view or include the
    # tag plugin into the search view
    view = bauble.gui.get_view()
    if isinstance(view, SearchView):
        values = view.get_selected_values()
        if len(values) == 0:
            msg = _('Nothing selected')
            utils.message_dialog(msg)
            return
        # right now we can only tag a single item at a time, if we did
        # the f-spot style quick tagging then it would be easier to handle
        # multiple tags at a time, we could do it we would just have to find
        # the common tags for each of the selected items and then select them
        # but grey them out so you can see that some of the items have that
        # tag but not all of them
        tagitem = TagItemGUI(values)
        tagitem.start()
        view.update_bottom_notebook()
    else:
        msg = _('In order to tag an item you must first search for '
                'something and select one of the results.')
        bauble.gui.show_message_box(msg)
Ejemplo n.º 29
0
    def __init__(self, *args, **kwargs):
        super(SchemaBrowser, self).__init__(*args, **kwargs)
        self.props.spacing = 10
        # WARNING: this is a hack from MapperSearch
        self.domain_map = {}
        self.domain_map = MapperSearch.get_domain_classes().copy()

        frame = gtk.Frame(_("Search Domain"))
        self.pack_start(frame, expand=False, fill=False)
        self.table_combo = gtk.combo_box_new_text()
        frame.add(self.table_combo)
        for key in sorted(self.domain_map.keys()):
            self.table_combo.append_text(key)

        self.table_combo.connect('changed', self.on_table_combo_changed)

        self.prop_tree = gtk.TreeView()
        self.prop_tree.set_headers_visible(False)
        cell = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Property"), cell)
        self.prop_tree.append_column(column)
        column.add_attribute(cell, 'text', 0)

        self.prop_tree.connect('test_expand_row', self.on_row_expanded)

        frame = gtk.Frame(_('Domain Properties'))
        sw = gtk.ScrolledWindow()
        sw.add(self.prop_tree)
        frame.add(sw)
        self.pack_start(frame, expand=True, fill=True)
Ejemplo n.º 30
0
def remove_callback(genera):
    """
    The callback function to remove a genus from the genus context menu.
    """
    genus = genera[0]
    from bauble.plugins.plants.species_model import Species
    session = db.Session()
    nsp = session.query(Species).filter_by(genus_id=genus.id).count()
    safe_str = utils.xml_safe(str(genus))
    if nsp > 0:
        msg = (_('The genus <i>%(genus)s</i> has %(num_species)s species.  '
                 'Are you sure you want to remove it?')
               % dict(genus=safe_str, num_species=nsp))
    else:
        msg = (_("Are you sure you want to remove the genus <i>%s</i>?")
               % safe_str)
    if not utils.yes_no_dialog(msg):
        return
    try:
        obj = session.query(Genus).get(genus.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _('Could not delete.\n\n%s') % utils.xml_safe(e)
        utils.message_details_dialog(msg, traceback.format_exc(),
                                     type=gtk.MESSAGE_ERROR)
Ejemplo n.º 31
0
    def start(self):
        """
        Show the connection manager.
        """
        self.create_gui()
        conn_list = prefs.prefs[bauble.conn_list_pref]
        if conn_list is None or len(conn_list.keys()) == 0:
            msg = _('You don\'t have any connections in your connection '
                    'list.\nClose this message and click on "Add" to create '
                    'a new connection.')
            utils.message_dialog(msg)
        else:
            self.set_active_connection_by_name(self.default_name)
            self._dirty = False

        self._error = True
        name = None
        uri = None
        while name is None or self._error:
            response = self.dialog.run()
            if response == gtk.RESPONSE_OK:
                name = self._get_connection_name()
                uri = self._get_connection_uri()
                if name is None:
                    msg = _('You have to choose or create a new connection '
                            'before you can connect to the database.')
                    utils.message_dialog(msg)
            else:
                name = uri = None
                break

        ## now make sure the pictures dir contains a thumbs subdir
        path = os.path.sep.join(
            (prefs.prefs[prefs.picture_root_pref], 'thumbs'))
        try:
            logger.debug("checking presence of thumbs dir")
            os.makedirs(path)
        except OSError:
            if not os.path.isdir(path):
                logger.debug("something wrong in thumbs dir")
                raise

        # have to remove the cell_data_func to avoid a cyclical
        # reference which would cause the ConnectionManager to not get
        # garbage collected
        cell = self.type_combo.get_cells()[0]
        self.type_combo.set_cell_data_func(cell, None)
        self.type_combo.clear()
        self.name_combo.clear()

        # just to be sure let's destroy the dialog upfront and delete
        # the params box
        self.dialog.destroy()
        del self.params_box
        obj = utils.gc_objects_by_type(CMParamsBox)
        if obj:
            logger.info('ConnectionManager.start(): param box leaked: %s'
                        % obj)
        return name, uri
Ejemplo n.º 32
0
    def start(self):
        """
        Show the connection manager.
        """
        self.create_gui()
        conn_list = prefs.prefs[bauble.conn_list_pref]
        if conn_list is None or len(conn_list.keys()) == 0:
            msg = _('You don\'t have any connections in your connection '
                    'list.\nClose this message and click on "Add" to create '
                    'a new connection.')
            utils.message_dialog(msg)
        else:
            self.set_active_connection_by_name(self.default_name)
            self._dirty = False

        self._error = True
        name = None
        uri = None
        while name is None or self._error:
            response = self.dialog.run()
            if response == gtk.RESPONSE_OK:
                name = self._get_connection_name()
                uri = self._get_connection_uri()
                if name is None:
                    msg = _('You have to choose or create a new connection '
                            'before you can connect to the database.')
                    utils.message_dialog(msg)
            else:
                name = uri = None
                break

        ## now make sure the pictures dir contains a thumbs subdir
        path = os.path.sep.join(
            (prefs.prefs[prefs.picture_root_pref], 'thumbs'))
        try:
            logger.debug("checking presence of thumbs dir")
            os.makedirs(path)
        except OSError:
            if not os.path.isdir(path):
                logger.debug("something wrong in thumbs dir")
                raise

        # have to remove the cell_data_func to avoid a cyclical
        # reference which would cause the ConnectionManager to not get
        # garbage collected
        cell = self.type_combo.get_cells()[0]
        self.type_combo.set_cell_data_func(cell, None)
        self.type_combo.clear()
        self.name_combo.clear()

        # just to be sure let's destroy the dialog upfront and delete
        # the params box
        self.dialog.destroy()
        del self.params_box
        obj = utils.gc_objects_by_type(CMParamsBox)
        if obj:
            logger.info('ConnectionManager.start(): param box leaked: %s' %
                        obj)
        return name, uri
Ejemplo n.º 33
0
def init(force=False):
    """
    Initialize the plugin manager.

    1. Check for and install any plugins in the plugins dict that
    aren't in the registry.
    2. Call each init() for each plugin the registry in order of dependency
    3. Register the command handlers in the plugin's commands[]

    NOTE: This should be called after after Bauble has established a
    connection to a database with db.open()
    """

    logger.debug('bauble.pluginmgr.init()')
    # ******
    # NOTE: Be careful not to keep any references to
    # PluginRegistry open here as it will cause a deadlock if you try
    # to create a new database. For example, don't query the
    # PluginRegistry with a session without closing the session.
    # ******

    # search for plugins that are in the plugins dict but not in the registry
    registered = plugins.values()
    logger.debug('registered plugins: %s' % plugins)
    try:
        # try to access the plugin registry, if the table does not exist
        # then it might mean that we are opening a pre 0.9 database, in this
        # case we just assume all the plugins have been installed and
        # registered, this might be the right thing to do but at least it
        # allows you to connect to a pre bauble 0.9 database and use it to
        # upgrade to a >=0.9 database
        registered_names = PluginRegistry.names()
        not_installed = [
            p for n, p in plugins.iteritems() if n not in registered_names
        ]
        if len(not_installed) > 0:
            msg = _('The following plugins were not found in the plugin '
                    'registry:\n\n<b>%s</b>\n\n'
                    '<i>Would you like to install them now?</i>' %
                    ', '.join([p.__class__.__name__ for p in not_installed]))
            if force or utils.yes_no_dialog(msg):
                install([p for p in not_installed])

        # sort plugins in the registry by their dependencies
        not_registered = []
        for name in PluginRegistry.names():
            try:
                registered.append(plugins[name])
            except KeyError, e:
                logger.debug("could not find '%s' plugin. "
                             "removing from database" % e)
                not_registered.append(utils.utf8(name))
                PluginRegistry.remove(name=name)

        if not_registered:
            msg = _('The following plugins are in the registry but '
                    'could not be loaded:\n\n%(plugins)s' %
                    {'plugins': utils.utf8(', '.join(sorted(not_registered)))})
            utils.message_dialog(utils.xml_safe(msg), type=gtk.MESSAGE_WARNING)
Ejemplo n.º 34
0
    def __export_task(self, path):
        filename_template = os.path.join(path, "%s.txt")
        steps_so_far = 0
        ntables = 0
        for table in db.metadata.sorted_tables:
            ntables += 1
            filename = filename_template % table.name
            if os.path.exists(filename):
                msg = _('Export file <b>%(filename)s</b> for '
                        '<b>%(table)s</b> table already exists.\n\n<i>Would '
                        'you like to continue?</i>')\
                    % {'filename': filename, 'table': table.name}
                if utils.yes_no_dialog(msg):
                    return

        def replace(s):
            if isinstance(s, (str, unicode)):
                s.replace('\n', '\\n')
            return s

        def write_csv(filename, rows):
            f = open(filename, 'wb')
            writer = UnicodeWriter(f,
                                   quotechar=QUOTE_CHAR,
                                   quoting=QUOTE_STYLE)
            writer.writerows(rows)
            f.close()

        update_every = 30
        for table in db.metadata.sorted_tables:
            filename = filename_template % table.name
            steps_so_far += 1
            fraction = float(steps_so_far) / float(ntables)
            pb_set_fraction(fraction)
            msg = _('exporting %(table)s table to %(filename)s')\
                % {'table': table.name, 'filename': filename}
            bauble.task.set_message(msg)
            logger.info("exporting %s" % table.name)

            # get the data
            results = table.select().execute().fetchall()

            # create empty files with only the column names
            if len(results) == 0:
                write_csv(filename, [table.c.keys()])
                yield
                continue

            rows = []
            rows.append(table.c.keys())  # append col names
            ctr = 0
            for row in results:
                values = map(replace, row.values())
                rows.append(values)
                if ctr == update_every:
                    yield
                    ctr = 0
                ctr += 1
            write_csv(filename, rows)
Ejemplo n.º 35
0
 def create_registry_view(self):
     #from bauble.pluginmgr import Registry
     from bauble.pluginmgr import PluginRegistry
     session = db.Session()
     plugins = session.query(PluginRegistry.name, PluginRegistry.version)
     tree = self.create_tree([_('Name'), _('Version')], plugins)
     session.close()
     return tree
Ejemplo n.º 36
0
class XMLExportTool(pluginmgr.Tool):
    category = _("Export")
    label = _("XML")

    @classmethod
    def start(cls):
        c = XMLExporter()
        c.start()
Ejemplo n.º 37
0
class CSVExportTool(pluginmgr.Tool):
    category = _('Export')
    label = _('Comma Separated Value')

    @classmethod
    def start(cls):
        c = CSVExporter()
        c.start()
Ejemplo n.º 38
0
    def __export_task(self, path):
        filename_template = os.path.join(path, "%s.txt")
        steps_so_far = 0
        ntables = 0
        for table in db.metadata.sorted_tables:
            ntables += 1
            filename = filename_template % table.name
            if os.path.exists(filename):
                msg = _('Export file <b>%(filename)s</b> for '
                        '<b>%(table)s</b> table already exists.\n\n<i>Would '
                        'you like to continue?</i>')\
                    % {'filename': filename, 'table': table.name}
                if utils.yes_no_dialog(msg):
                    return

        def replace(s):
            if isinstance(s, (str, unicode)):
                s.replace('\n', '\\n')
            return s

        def write_csv(filename, rows):
            f = open(filename, 'wb')
            writer = UnicodeWriter(f, quotechar=QUOTE_CHAR,
                                   quoting=QUOTE_STYLE)
            writer.writerows(rows)
            f.close()

        update_every = 30
        for table in db.metadata.sorted_tables:
            filename = filename_template % table.name
            steps_so_far += 1
            fraction = float(steps_so_far)/float(ntables)
            pb_set_fraction(fraction)
            msg = _('exporting %(table)s table to %(filename)s')\
                % {'table': table.name, 'filename': filename}
            bauble.task.set_message(msg)
            logger.info("exporting %s" % table.name)

            # get the data
            results = table.select().execute().fetchall()

            # create empty files with only the column names
            if len(results) == 0:
                write_csv(filename, [table.c.keys()])
                yield
                continue

            rows = []
            rows.append(table.c.keys())  # append col names
            ctr = 0
            for row in results:
                values = map(replace, row.values())
                rows.append(values)
                if ctr == update_every:
                    yield
                    ctr = 0
                ctr += 1
            write_csv(filename, rows)
Ejemplo n.º 39
0
def init(force=False):
    """
    Initialize the plugin manager.

    1. Check for and install any plugins in the plugins dict that
    aren't in the registry.
    2. Call each init() for each plugin the registry in order of dependency
    3. Register the command handlers in the plugin's commands[]

    NOTE: This is called after after Ghini has created the GUI and
    established a connection to a database with db.open()

    """
    logger.debug('bauble.pluginmgr.init()')
    # ******
    # NOTE: Be careful not to keep any references to
    # PluginRegistry open here as it will cause a deadlock if you try
    # to create a new database. For example, don't query the
    # PluginRegistry with a session without closing the session.
    # ******

    # search for plugins that are in the plugins dict but not in the registry
    registered = plugins.values()
    logger.debug('registered plugins: %s' % plugins)
    try:
        # try to access the plugin registry, if the table does not exist
        # then it might mean that we are opening a pre 0.9 database, in this
        # case we just assume all the plugins have been installed and
        # registered, this might be the right thing to do but at least it
        # allows you to connect to a pre bauble 0.9 database and use it to
        # upgrade to a >=0.9 database
        registered_names = PluginRegistry.names()
        not_installed = [p for n, p in plugins.iteritems()
                         if n not in registered_names]
        if len(not_installed) > 0:
            msg = _('The following plugins were not found in the plugin '
                    'registry:\n\n<b>%s</b>\n\n'
                    '<i>Would you like to install them now?</i>') % \
                ', '.join([p.__class__.__name__ for p in not_installed])
            if force or utils.yes_no_dialog(msg):
                install([p for p in not_installed])

        # sort plugins in the registry by their dependencies
        not_registered = []
        for name in PluginRegistry.names():
            try:
                registered.append(plugins[name])
            except KeyError, e:
                logger.debug("could not find '%s' plugin. "
                             "removing from database" % e)
                not_registered.append(utils.utf8(name))
                PluginRegistry.remove(name=name)

        if not_registered:
            msg = _('The following plugins are in the registry but '
                    'could not be loaded:\n\n%(plugins)s') % \
                {'plugins': utils.utf8(', '.join(sorted(not_registered)))}
            utils.message_dialog(utils.xml_safe(msg), type=gtk.MESSAGE_WARNING)
Ejemplo n.º 40
0
 def create_registry_view(self):
     #from bauble.pluginmgr import Registry
     from bauble.pluginmgr import PluginRegistry
     session = db.Session()
     plugins = session.query(PluginRegistry.name, PluginRegistry.version)
     tree = self.create_tree([_('Name'), _('Version')],
                             plugins)
     session.close()
     return tree
Ejemplo n.º 41
0
def start_institution_editor():
    glade_path = os.path.join(paths.lib_dir(), "plugins", "garden", "institution.glade")
    from bauble import prefs
    from bauble.editor import GenericEditorView, MockView

    if prefs.testing:
        view = MockView()
    else:
        view = GenericEditorView(glade_path, parent=None, root_widget_name="inst_dialog")
    view._tooltips = {
        "inst_name": _("The full name of the institution."),
        "inst_abbr": _("The standard abbreviation of the " "institution."),
        "inst_code": _("The intitution code should be unique among " "all institions."),
        "inst_contact": _("The name of the person to contact for " "information related to the institution."),
        "inst_tech": _(
            "The email address or phone number of the "
            "person to contact for technical "
            "information related to the institution."
        ),
        "inst_email": _("The email address of the institution."),
        "inst_tel": _("The telephone number of the institution."),
        "inst_fax": _("The fax number of the institution."),
        "inst_addr": _("The mailing address of the institition."),
    }

    o = Institution()
    inst_pres = InstitutionPresenter(o, view)
    response = inst_pres.start()
    if response == gtk.RESPONSE_OK:
        o.write()
        inst_pres.commit_changes()
    else:
        inst_pres.session.rollback()
    inst_pres.session.close()
Ejemplo n.º 42
0
class InstitutionEditorView(editor.GenericEditorView):

    _tooltips = {'inst_name': _('The full name of the institution.'),
                 'inst_abbr': _('The standard abbreviation of the '
                                'institution.'),
                 'inst_code': _('The intitution code should be unique among '
                                'all institions.'),
                 'inst_contact': _('The name of the person to contact for '
                                   'information related to the institution.'),
                 'inst_tech': _('The email address or phone number of the '
                                'person to contact for technical '
                                'information related to the institution.'),
                 'inst_email': _('The email address of the institution.'),
                 'inst_tel': _('The telephone number of the institution.'),
                 'inst_fax': _('The fax number of the institution.'),
                 'inst_addr': _('The mailing address of the institition.')
                 }

    def __init__(self, parent=None):
        filename = os.path.join(paths.lib_dir(), 'plugins', 'garden',
                                'institution.glade')
        super(InstitutionEditorView, self).__init__(filename, parent=parent)

    def get_window(self):
        return self.widgets.inst_dialog

    def start(self):
        return self.get_window().run()
Ejemplo n.º 43
0
    def condition(self):
        """the condition of this taxon, or None

        this is referred to what the garden conservator considers the
        area of interest. it is really an interpretation, not a fact.
        """
        # one of, but not forcibly so:
        [_("endemic"), _("indigenous"), _("native"), _("introduced")]

        notes = [i.note for i in self.notes if i.category.lower() == u"condition"]
        return (notes + [None])[0]
Ejemplo n.º 44
0
class PicasaSettingsTool(pluginmgr.Tool):
    """
    Tool for changing the Picasa settings and updated the auth token
    """
    category = _('Picasa')
    label = _('Settings')

    @classmethod
    def start(cls):
        d = PicasaSettingsDialog()
        d.run()
Ejemplo n.º 45
0
class JSONExportTool(pluginmgr.Tool):
    category = _('Export')
    label = _('JSON')

    @classmethod
    def start(cls):
        # the presenter uses the view to interact with user then
        # performs the export, if this is the case.
        s = db.Session()
        presenter = JSONExporter(view=ExportToJson(s))
        presenter.start()  # interact && run
        s.close()
Ejemplo n.º 46
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)
Ejemplo n.º 47
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)
Ejemplo n.º 48
0
    def condition(self):
        '''the condition of this taxon, or None

        this is referred to what the garden conservator considers the
        area of interest. it is really an interpretation, not a fact.
        '''
        # one of, but not forcibly so:
        [_('endemic'), _('indigenous'), _('native'), _('introduced')]

        notes = [i.note for i in self.notes
                 if i.category.lower() == u'condition']
        return (notes + [None])[0]
Ejemplo n.º 49
0
    def condition(self):
        '''the condition of this taxon, or None

        this is referred to what the garden conservator considers the
        area of interest. it is really an interpretation, not a fact.
        '''
        # one of, but not forcibly so:
        [_('endemic'), _('indigenous'), _('native'), _('introduced')]

        notes = [i.note for i in self.notes
                 if i.category.lower() == u'condition']
        return (notes + [None])[0]
Ejemplo n.º 50
0
def verify_connection(engine, show_error_dialogs=False):
    """
    Test whether a connection to an engine is a valid Bauble database. This
    method will raise an error for the first problem it finds with the
    database.

    :param engine: the engine to test
    :type engine: :class:`sqlalchemy.engine.Engine`
    :param show_error_dialogs: flag for whether or not to show message
        dialogs detailing the error, default=False
    :type show_error_dialogs: bool
    """
    ##    debug('entered verify_connection(%s)' % show_error_dialogs)
    import bauble

    if show_error_dialogs:
        try:
            return verify_connection(engine, False)
        except error.EmptyDatabaseError:
            msg = _("The database you have connected to is empty.")
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            raise
        except error.MetaTableError:
            msg = _(
                "The database you have connected to does not have the "
                "bauble meta table.  This usually means that the database "
                "is either corrupt or it was created with an old version "
                "of Bauble"
            )
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            raise
        except error.TimestampError:
            msg = _(
                "The database you have connected to does not have a "
                "timestamp for when it was created. This usually means "
                "that there was a problem when you created the "
                "database or the database you connected to wasn't "
                "created with Bauble."
            )
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            raise
        except error.VersionError, e:
            msg = _(
                "You are using Bauble version %(version)s while the "
                "database you have connected to was created with "
                "version %(db_version)s\n\nSome things might not work as "
                "or some of your data may become unexpectedly "
                "corrupted."
            ) % {"version": bauble.version, "db_version": "%s" % e.version}
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            raise
Ejemplo n.º 51
0
    def check_parameters_valid(self):
        """
        check that all of the information in the current connection
        is valid and return true or false

        NOTE: this was meant to be used to implement an eclipse style
        information box at the top of the dialog but it's not really
        used right now
        """
        if self.name_combo.get_active_text() == "":
            return False, _("Please choose a name for this connection")
        params = self.params_box
        if params["user"] == "":
            return False, _("Please choose a user name for this connection")
Ejemplo n.º 52
0
    def on_dialog_response(self, dialog, response, data=None):
        """
        The dialog's response signal handler.
        """
        self._error = False
        if response == gtk.RESPONSE_OK:
            settings = self.params_box.get_prefs()
            dbtype = self.widgets.type_combo.get_active_text()
            if dbtype == 'SQLite':
                filename = settings['file']
                if not os.path.exists(filename):
                    path, f = os.path.split(filename)
                    if not os.access(path, os.R_OK):
                        self._error = True
                        msg = _("Bauble does not have permission to "
                                "read the directory:\n\n%s") % path
                        utils.message_dialog(msg, gtk.MESSAGE_ERROR)
                    elif not os.access(path, os.W_OK):
                        self._error = True
                        msg = _("Bauble does not have permission to "
                                "write to the directory:\n\n%s") % path
                        utils.message_dialog(msg, gtk.MESSAGE_ERROR)
                elif not os.access(filename, os.R_OK):
                    self._error = True
                    msg = _("Bauble does not have permission to read the "
                            "database file:\n\n%s") % filename
                    utils.message_dialog(msg, gtk.MESSAGE_ERROR)
                elif not os.access(filename, os.W_OK):
                    self._error = True
                    msg = _("Bauble does not have permission to "
                            "write to the database file:\n\n%s") % filename
                    utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            if not self._error:
                self.save_current_to_prefs()
                prefs.prefs[prefs.picture_root_pref] = settings.get(
                    'pictures', '')
        elif response == gtk.RESPONSE_CANCEL or \
                response == gtk.RESPONSE_DELETE_EVENT:
            if not self.compare_prefs_to_saved(self.current_name):
                msg = _("Do you want to save your changes?")
                if utils.yes_no_dialog(msg):
                    self.save_current_to_prefs()

        # system-defined GtkDialog responses are always negative, in which
        # case we want to hide it
        if response < 0:
            dialog.hide()
            #dialog.emit_stop_by_name('response')

        return response
Ejemplo n.º 53
0
    def check_parameters_valid(self):
        """
        check that all of the information in the current connection
        is valid and return true or false

        NOTE: this was meant to be used to implement an eclipse style
        information box at the top of the dialog but it's not really
        used right now
        """
        if self.name_combo.get_active_text() == "":
            return False, _("Please choose a name for this connection")
        params = self.params_box
        if params["user"] == "":
            return False, _("Please choose a user name for this connection")
Ejemplo n.º 54
0
    def on_dialog_response(self, dialog, response, data=None):
        """
        The dialog's response signal handler.
        """
        self._error = False
        if response == gtk.RESPONSE_OK:
            settings = self.params_box.get_prefs()
            dbtype = self.widgets.type_combo.get_active_text()
            if dbtype == 'SQLite':
                filename = settings['file']
                if not os.path.exists(filename):
                    path, f = os.path.split(filename)
                    if not os.access(path, os.R_OK):
                        self._error = True
                        msg = _("Bauble does not have permission to "
                                "read the directory:\n\n%s") % path
                        utils.message_dialog(msg, gtk.MESSAGE_ERROR)
                    elif not os.access(path, os.W_OK):
                        self._error = True
                        msg = _("Bauble does not have permission to "
                                "write to the directory:\n\n%s") % path
                        utils.message_dialog(msg, gtk.MESSAGE_ERROR)
                elif not os.access(filename, os.R_OK):
                    self._error = True
                    msg = _("Bauble does not have permission to read the "
                            "database file:\n\n%s") % filename
                    utils.message_dialog(msg, gtk.MESSAGE_ERROR)
                elif not os.access(filename, os.W_OK):
                    self._error = True
                    msg = _("Bauble does not have permission to "
                            "write to the database file:\n\n%s") % filename
                    utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            if not self._error:
                self.save_current_to_prefs()
                prefs.prefs[prefs.picture_root_pref] = settings.get(
                    'pictures', '')
        elif response == gtk.RESPONSE_CANCEL or \
                response == gtk.RESPONSE_DELETE_EVENT:
            if not self.compare_prefs_to_saved(self.current_name):
                msg = _("Do you want to save your changes?")
                if utils.yes_no_dialog(msg):
                    self.save_current_to_prefs()

        # system-defined GtkDialog responses are always negative, in which
        # case we want to hide it
        if response < 0:
            dialog.hide()
            #dialog.emit_stop_by_name('response')

        return response
Ejemplo n.º 55
0
    def init(cls):
        if 'GardenPlugin' in pluginmgr.plugins:
            species_context_menu.insert(1, add_accession_action)
            vernname_context_menu.insert(1, add_accession_action)

        mapper_search = search.get_strategy('MapperSearch')

        mapper_search.add_meta(('family', 'fam'), Family, ['family'])
        SearchView.row_meta[Family].set(children="genera",
                                        infobox=FamilyInfoBox,
                                        context_menu=family_context_menu)

        mapper_search.add_meta(('genus', 'gen'), Genus, ['genus'])
        SearchView.row_meta[Genus].set(children="species",
                                       infobox=GenusInfoBox,
                                       context_menu=genus_context_menu)

        from functools import partial
        search.add_strategy(SynonymSearch)
        mapper_search.add_meta(
            ('species', 'sp'), Species,
            ['sp', 'sp2', 'infrasp1', 'infrasp2', 'infrasp3', 'infrasp4'])
        SearchView.row_meta[Species].set(children=partial(
            db.natsort, 'accessions'),
                                         infobox=SpeciesInfoBox,
                                         context_menu=species_context_menu)

        mapper_search.add_meta(('vernacular', 'vern', 'common'),
                               VernacularName, ['name'])
        SearchView.row_meta[VernacularName].set(
            children=partial(db.natsort, 'species.accessions'),
            infobox=VernacularNameInfoBox,
            context_menu=vernname_context_menu)

        mapper_search.add_meta(('geography', 'geo'), Geography, ['name'])
        SearchView.row_meta[Geography].set(children=get_species_in_geography)

        ## now it's the turn of the DefaultView
        logger.debug('PlantsPlugin::init, registering splash info box')
        DefaultView.infoboxclass = SplashInfoBox

        if bauble.gui is not None:
            bauble.gui.add_to_insert_menu(FamilyEditor, _('Family'))
            bauble.gui.add_to_insert_menu(GenusEditor, _('Genus'))
            bauble.gui.add_to_insert_menu(SpeciesEditorMenuItem, _('Species'))

        if sys.platform == 'win32':
            # TODO: for some reason using the cross as the hybrid
            # character doesn't work on windows
            Species.hybrid_char = 'x'
Ejemplo n.º 56
0
def source_detail_remove_callback(details):
    detail = details[0]
    s = "%s: %s" % (detail.__class__.__name__, str(detail))
    msg = _("Are you sure you want to remove %s?") % utils.xml_safe(s)
    if not utils.yes_no_dialog(msg):
        return
    try:
        session = db.Session()
        obj = session.query(SourceDetail).get(detail.id)
        session.delete(obj)
        session.commit()
    except Exception, e:
        msg = _("Could not delete.\n\n%s") % utils.xml_safe(e)
        utils.message_details_dialog(msg, traceback.format_exc(), type=gtk.MESSAGE_ERROR)
Ejemplo n.º 57
0
    def init(cls):
        if 'GardenPlugin' in pluginmgr.plugins:
            species_context_menu.insert(1, add_accession_action)
            vernname_context_menu.insert(1, add_accession_action)

        mapper_search = search.get_strategy('MapperSearch')

        mapper_search.add_meta(('family', 'fam'), Family, ['family'])
        SearchView.row_meta[Family].set(children="genera",
                                        infobox=FamilyInfoBox,
                                        context_menu=family_context_menu)

        mapper_search.add_meta(('genus', 'gen'), Genus, ['genus'])
        SearchView.row_meta[Genus].set(children="species",
                                       infobox=GenusInfoBox,
                                       context_menu=genus_context_menu)

        from functools import partial
        search.add_strategy(SynonymSearch)
        mapper_search.add_meta(('species', 'sp'), Species,
                               ['sp', 'sp2', 'infrasp1', 'infrasp2',
                                'infrasp3', 'infrasp4'])
        SearchView.row_meta[Species].set(
            children=partial(db.natsort, 'accessions'),
            infobox=SpeciesInfoBox,
            context_menu=species_context_menu)

        mapper_search.add_meta(('vernacular', 'vern', 'common'),
                               VernacularName, ['name'])
        SearchView.row_meta[VernacularName].set(
            children=partial(db.natsort, 'species.accessions'),
            infobox=VernacularNameInfoBox,
            context_menu=vernname_context_menu)

        mapper_search.add_meta(('geography', 'geo'), Geography, ['name'])
        SearchView.row_meta[Geography].set(children=get_species_in_geography)

        ## now it's the turn of the DefaultView
        logger.debug('PlantsPlugin::init, registering splash info box')
        DefaultView.infoboxclass = SplashInfoBox

        if bauble.gui is not None:
            bauble.gui.add_to_insert_menu(FamilyEditor, _('Family'))
            bauble.gui.add_to_insert_menu(GenusEditor, _('Genus'))
            bauble.gui.add_to_insert_menu(SpeciesEditorMenuItem, _('Species'))

        if sys.platform == 'win32':
            # TODO: for some reason using the cross as the hybrid
            # character doesn't work on windows
            Species.hybrid_char = 'x'
Ejemplo n.º 58
0
    def init(cls):
        if 'GardenPlugin' in pluginmgr.plugins:
            species_context_menu.insert(1, add_accession_action)
            vernname_context_menu.insert(1, add_accession_action)

        mapper_search = search.get_strategy('MapperSearch')

        mapper_search.add_meta(('family', 'fam'), Family, ['family'])
        SearchView.view_meta[Family].set(children="genera",
                                         infobox=FamilyInfoBox,
                                         context_menu=family_context_menu,
                                         markup_func=family_markup_func)

        mapper_search.add_meta(('genus', 'gen'), Genus, ['genus'])
        SearchView.view_meta[Genus].set(children="species",
                                        infobox=GenusInfoBox,
                                        context_menu=genus_context_menu,
                                        markup_func=genus_markup_func)

        search.add_strategy(SynonymSearch)
        mapper_search.add_meta(('species', 'sp'), Species,
                               ['sp', 'sp2', 'infrasp1', 'infrasp2',
                                'infrasp3', 'infrasp4'])
        SearchView.view_meta[Species].set(children=species_get_kids,
                                          infobox=SpeciesInfoBox,
                                          context_menu=species_context_menu,
                                          markup_func=species_markup_func)

        mapper_search.add_meta(('vernacular', 'vern', 'common'),
                               VernacularName, ['name'])
        SearchView.view_meta[VernacularName].set(
            children=vernname_get_kids,
            infobox=VernacularNameInfoBox,
            context_menu=vernname_context_menu,
            markup_func=vernname_markup_func)

        mapper_search.add_meta(('geography', 'geo'), Geography, ['name'])
        SearchView.view_meta[Geography].set(children=get_species_in_geography)

        if bauble.gui is not None:
            bauble.gui.add_to_insert_menu(FamilyEditor, _('Family'))
            bauble.gui.add_to_insert_menu(GenusEditor, _('Genus'))
            bauble.gui.add_to_insert_menu(SpeciesEditorMenuItem, _('Species'))

        if sys.platform == 'win32':
            # TODO: for some reason using the cross as the hybrid
            # character doesn't work on windows
            Species.hybrid_char = 'x'
Ejemplo n.º 59
0
    def __init__(self):
        """
        the constructor
        """
        super(SpeciesInfoPage, self).__init__()
        filename = os.path.join(paths.lib_dir(), "plugins", "plants", "infoboxes.glade")
        # load the widgets directly instead of using load_widgets()
        # because the caching that load_widgets() does can mess up
        # displaying the SpeciesInfoBox sometimes if you try to show
        # the infobox while having a vernacular names selected in
        # the search results and then a species name
        self.widgets = utils.BuilderWidgets(filename)
        self.general = GeneralSpeciesExpander(self.widgets)
        self.add_expander(self.general)
        self.vernacular = VernacularExpander(self.widgets)
        self.add_expander(self.vernacular)
        self.synonyms = SynonymsExpander(self.widgets)
        self.add_expander(self.synonyms)
        self.links = LinksExpander()
        self.add_expander(self.links)
        self.props = PropertiesExpander()
        self.add_expander(self.props)
        self.label = _("General")

        if "GardenPlugin" not in pluginmgr.plugins:
            self.widgets.remove_parent("sp_nacc_label")
            self.widgets.remove_parent("sp_nacc_data")
            self.widgets.remove_parent("sp_nplants_label")
            self.widgets.remove_parent("sp_nplants_data")