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)
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: debug(e) 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 run(self, filename, plants=None): if filename == None: raise ValueError("filename can not be None") if os.path.exists(filename) and not os.path.isfile(filename): raise ValueError("%s exists and is not a a regular file" \ % filename) # if plants is None then export all plants, this could be huge # TODO: do something about this, like list the number of plants # to be returned and make sure this is what the user wants if plants == None: plants = db.Session().query(Plant).all() # TODO: move PlantABCDAdapter, AccessionABCDAdapter and # PlantABCDAdapter into the ABCD plugin from bauble.plugins.report.xsl import PlantABCDAdapter data = create_abcd([PlantABCDAdapter(p) for p in plants], validate=False) data.write_c14n(filename) # validate after the file is written so we still have some # output but let the user know the file isn't valid ABCD if not validate_xml(data): msg = _("The ABCD file was created but failed to validate " "correctly against the ABCD standard.") utils.message_dialog(msg, gtk.MESSAGE_WARNING)
def run(self): """ """ response = self.window.run() self.window.hide() if response != gtk.RESPONSE_OK: return response stored_email = meta.get_default(PICASA_EMAIL_KEY).value.strip() email = self.widgets.email_entry.get_text().strip() album = self.widgets.album_entry.get_text().strip() passwd = self.widgets.password_entry.get_text().strip() if stored_email != email or self._changed: try: token = get_auth_token(email, passwd) except Exception, e: debug(e) token = None if not token: utils.message_dialog(_('Could not authorize Google '\ 'account: %s' % email), gtk.MESSAGE_ERROR) return False update_meta(utils.utf8(email), utils.utf8(album), utils.utf8(token))
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
def run(self): """ """ response = self.window.run() self.window.hide() if response != gtk.RESPONSE_OK: return response stored_email = meta.get_default(PICASA_EMAIL_KEY).value.strip() email = self.widgets.email_entry.get_text().strip() album = self.widgets.album_entry.get_text().strip() passwd = self.widgets.password_entry.get_text().strip() if stored_email != email or self._changed: try: token = get_auth_token(email, passwd) except Exception, e: logger.debug(e) token = None if not token: utils.message_dialog( _('Could not authorize Google ' 'account: %s' % email), gtk.MESSAGE_ERROR) return False update_meta(utils.utf8(email), utils.utf8(album), utils.utf8(token))
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
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_utf8(e) utils.message_dialog(msg, gtk.MESSAGE_ERROR) return
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
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 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
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)
def init_names_combo(self): formatters = prefs[config_list_pref] if formatters is None or len(formatters) == 0: msg = _('No formatters found. To create a new formatter click '\ 'the "New" button.') utils.message_dialog(msg, parent=self.view.dialog) self.view.widgets.names_combo.set_model(None) self.populate_names_combo()
def init_names_combo(self): formatters = prefs[config_list_pref] if formatters is None or len(formatters) == 0: msg = _('No formatters found. To create a new formatter click ' 'the "New" button.') utils.message_dialog(msg, parent=self.view.dialog) self.view.widgets.names_combo.set_model(None) self.populate_names_combo()
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)
def branch_callback(plants): if plants[0].quantity <= 1: msg = _("Not enough plants to branch. A plant should have at least " "a quantity of 2 before it can be branched") utils.message_dialog(msg, gtk.MESSAGE_WARNING) return e = PlantEditor(model=plants[0], branch_mode=True) return e.start() != None
def __init__(self, ): """ """ filename = os.path.join(paths.lib_dir(), 'plugins', 'users', 'ui.glade') super(UsersEditor, self).__init__(filename) if db.engine.name not in ('postgres', 'postgresql'): msg = _('The Users editor is only valid on a PostgreSQL database') utils.message_dialog(utils.utf8(msg)) return # TODO: should allow anyone to view the priveleges but only # admins to change them #debug(current_user()) if not has_privileges(current_user(), 'admin'): msg = _('You do not have privileges to change other '\ 'user privileges') utils.message_dialog(utils.utf8(msg)) return # setup the users tree tree = self.widgets.users_tree # remove any old columns for column in tree.get_columns(): tree.remove_column(column) renderer = gtk.CellRendererText() def cell_data_func(col, cell, model, it): value = model[it][0] cell.set_property('text', value) tree.insert_column_with_data_func(0, _('Users'), renderer, cell_data_func) self.connect(tree, 'cursor-changed', self.on_cursor_changed) self.connect(renderer, 'edited', self.on_cell_edited) # connect the filter_check and also adds the users to the users_tree self.connect('filter_check', 'toggled', self.on_filter_check_toggled) self.widgets.filter_check.set_active(True) def on_toggled(button, priv=None): buttons = (self.widgets.read_button, self.widgets.write_button, self.widgets.admin_button) role = self.get_selected_user() active = button.get_active() if active and not has_privileges(role, priv): #debug('grant %s to %s' % (priv, role)) try: set_privilege(role, priv) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window()) return True
def on_toggled(button, priv=None): buttons = (self.widgets.read_button, self.widgets.write_button, self.widgets.admin_button) role = self.get_selected_user() active = button.get_active() if active and not has_privileges(role, priv): # debug('grant %s to %s' % (priv, role)) try: set_privilege(role, priv) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window())
def on_toggled(button, priv=None): buttons = (self.widgets.read_button, self.widgets.write_button, self.widgets.admin_button) role = self.get_selected_user() active = button.get_active() if active and not has_privileges(role, priv): #debug('grant %s to %s' % (priv, role)) try: set_privilege(role, priv) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window())
def __init__(self, ): """ """ filename = os.path.join( paths.lib_dir(), 'plugins', 'users', 'ui.glade') super(UsersEditor, self).__init__(filename) if db.engine.name not in ('postgres', 'postgresql'): msg = _('The Users editor is only valid on a PostgreSQL database') utils.message_dialog(utils.utf8(msg)) return # TODO: should allow anyone to view the priveleges but only # admins to change them #debug(current_user()) if not has_privileges(current_user(), 'admin'): msg = _('You do not have privileges to change other '\ 'user privileges') utils.message_dialog(utils.utf8(msg)) return # setup the users tree tree = self.widgets.users_tree # remove any old columns for column in tree.get_columns(): tree.remove_column(column) renderer = gtk.CellRendererText() def cell_data_func(col, cell, model, it): value = model[it][0] cell.set_property('text', value) tree.insert_column_with_data_func(0, _('Users'), renderer, cell_data_func) self.connect(tree, 'cursor-changed', self.on_cursor_changed) self.connect(renderer, 'edited', self.on_cell_edited) # connect the filter_check and also adds the users to the users_tree self.connect('filter_check', 'toggled', self.on_filter_check_toggled) self.widgets.filter_check.set_active(True) def on_toggled(button, priv=None): buttons = (self.widgets.read_button, self.widgets.write_button, self.widgets.admin_button) role = self.get_selected_user() active = button.get_active() if active and not has_privileges(role, priv): #debug('grant %s to %s' % (priv, role)) try: set_privilege(role, priv) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window()) return True
def save(self): try: f = open(self._filename, "w+") self.config.write(f) f.close() except Exception: msg = _("Bauble can't save your user preferences. \n\nPlease " "check the file permissions of your config file:\n %s" \ % self._filename) if bauble.gui is not None and bauble.gui.window is not None: import bauble.utils as utils utils.message_dialog(msg, type=gtk.MESSAGE_ERROR, parent=bauble.gui.window)
def start(self): """ Show the connection manager. """ self.create_gui() self.dialog.connect('response', self.on_dialog_response) self.dialog.connect('close', self.on_dialog_close_or_delete) self.dialog.connect('delete-event', self.on_dialog_close_or_delete) conn_list = 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 # 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: warning('ConnectionManager.start(): param box leaked: %s' % obj) return name, uri
def save(self): try: f = open(self._filename, "w+") self.config.write(f) f.close() except Exception: msg = _("Bauble can't save your user preferences. \n\nPlease " "check the file permissions of your config file:\n %s" % self._filename) if bauble.gui is not None and bauble.gui.window is not None: import bauble.utils as utils utils.message_dialog(msg, type=gtk.MESSAGE_ERROR, parent=bauble.gui.window)
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) return while True: response = self.presenter.start() self.presenter.view.save_state() if self.handle_response(response): break self.presenter.cleanup() self.session.close() # cleanup session return self._committed
def on_cell_edited(self, cell, path, new_text, data=None): model = self.widgets.users_tree.get_model() user = new_text if user == self.new_user_message: # didn't change so don't add the user treeiter = model.get_iter((len(model) - 1,)) model.remove(treeiter) return True model[path] = (user,) try: create_user(user) set_privilege(user, "read") except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window()) model.remove(model.get_iter(path))
def start(self): if self.session.query(Genus).count() == 0: msg = _("You must first add or import at least one genus into the " "database before you can add species.") utils.message_dialog(msg) return while True: response = self.presenter.start() self.presenter.view.save_state() if self.handle_response(response): break self.presenter.cleanup() self.session.close() # cleanup session return self._committed
def on_remove_button_clicked(self, button, *args): """ """ user = self.get_selected_user() msg = _( "Are you sure you want to remove user <b>%(name)s</b>?\n\n" "<i>It is possible that this user could have permissions " "on other databases not related to Ghini.</i>" ) % {"name": user} if not utils.yes_no_dialog(msg): return try: drop(user, revoke=True) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window())
def on_remove_button_clicked(self, button, *args): """ """ user = self.get_selected_user() msg = _('Are you sure you want to remove user <b>%(name)s</b>?\n\n' '<i>It is possible that this user could have permissions ' 'on other databases not related to Bauble.</i>') \ % {'name': user} if not utils.yes_no_dialog(msg): return try: drop(user, revoke=True) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window())
def on_cell_edited(self, cell, path, new_text, data=None): model = self.widgets.users_tree.get_model() user = new_text if user == self.new_user_message: # didn't change so don't add the user treeiter = model.get_iter((len(model)-1,)) model.remove(treeiter) return True model[path] = (user,) try: create_user(user) set_privilege(user, 'read') except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window()) model.remove(model.get_iter(path))
def save(self, force=False): if testing and not force: return try: f = open(self._filename, "w+") self.config.write(f) f.close() except Exception: msg = _("Bauble can't save your user preferences. \n\nPlease " "check the file permissions of your config file:\n %s") \ % self._filename if bauble.gui is not None and bauble.gui.window is not None: import bauble.utils as utils utils.message_dialog(msg, type=gtk.MESSAGE_ERROR, parent=bauble.gui.window) else: logger.error(msg)
def remove_callback(locations): loc = locations[0] s = "%s: %s" % (loc.__class__.__name__, str(loc)) if len(loc.plants) > 0: msg = _("Please remove the plants from <b>%(location)s</b> " "before deleting it.") % {"location": loc} utils.message_dialog(msg, gtk.MESSAGE_WARNING) return 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(Location).get(loc.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)
def create_gui(self): if self.working_dbtypes is None or len(self.working_dbtypes) == 0: msg = _("No Python database connectors installed.\n"\ "Please consult the documentation for the "\ "prerequesites for installing Bauble.") utils.message_dialog(msg, gtk.MESSAGE_ERROR) raise Exception(msg) glade_path = os.path.join(paths.lib_dir(), "connmgr.glade") self.widgets = utils.BuilderWidgets(glade_path) self.dialog = self.widgets.main_dialog try: pixbuf = gtk.gdk.pixbuf_new_from_file(bauble.default_icon) self.dialog.set_icon(pixbuf) except Exception, e: warning(_('Could not load icon from %s' % bauble.default_icon)) warning(traceback.format_exc())
def save(self, force=False): if testing and not force: return try: f = open(self._filename, "w+") self.config.write(f) f.close() except Exception: msg = _("Ghini can't save your user preferences. \n\nPlease " "check the file permissions of your config file:\n %s") \ % self._filename if bauble.gui is not None and bauble.gui.window is not None: import bauble.utils as utils utils.message_dialog(msg, type=gtk.MESSAGE_ERROR, parent=bauble.gui.window) else: logger.error(msg)
def refresh_view(self, default_vernacular_name): tree_model = self.treeview.get_model() #if len(self.model) > 0 and default_vernacular_name is None: vernacular_names = self.model.vernacular_names default_vernacular_name = self.model.default_vernacular_name if len(vernacular_names) > 0 and default_vernacular_name is None: msg = _('This species has vernacular names but none of them are ' 'selected as the default. The first vernacular name in ' 'the list has been automatically selected.') utils.message_dialog(msg) first = tree_model.get_iter_first() value = tree_model[first][0] path = tree_model.get_path(first) #self.set_model_attr('default_vernacular_name', value) self.model.default_vernacular_name = value self._dirty = True self.parent_ref().refresh_sensitivity() elif default_vernacular_name is None: return
def init_formatter_combo(self): plugins = [] for p in pluginmgr.plugins.values(): if issubclass(p, FormatterPlugin): plugins.append(p) # we should always have at least the default formatter model = gtk.ListStore(str) #assert len(plugins) is not 0, 'No formatter plugins defined.' if len(plugins) == 0: utils.message_dialog(_('No formatter plugins defined'), gtk.MESSAGE_WARNING) return for item in plugins: title = item.title self.formatter_class_map[title] = item model.append([item.title]) self.view.widgets.formatter_combo.set_model(model)
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
def remove_callback(locations): loc = locations[0] s = '%s: %s' % (loc.__class__.__name__, str(loc)) if len(loc.plants) > 0: msg = _('Please remove the plants from <b>%(location)s</b> ' 'before deleting it.') % {'location': loc} utils.message_dialog(msg, gtk.MESSAGE_WARNING) return 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(Location).get(loc.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)
def init_formatter_combo(self): plugins = [] for p in pluginmgr.plugins.values(): if isinstance(p, FormatterPlugin): logger.debug('recognized %s as a FormatterPlugin', p) plugins.append(p) else: logger.debug('discarded %s: not a FormatterPlugin', p) # we should always have at least the default formatter model = gtk.ListStore(str) if len(plugins) == 0: utils.message_dialog(_('No formatter plugins defined'), gtk.MESSAGE_WARNING) return for item in plugins: title = item.title self.formatter_class_map[title] = item model.append([item.title]) self.view.widgets.formatter_combo.set_model(model)
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
def on_pwd_button_clicked(self, button, *args): dialog = self.widgets.pwd_dialog dialog.set_transient_for(self.get_window()) def _on_something(d, *args): d.hide() return True self.connect(dialog, "delete-event", _on_something) self.connect(dialog, "close", _on_something) self.connect(dialog, "response", _on_something) self.widgets.pwd_entry1.set_text("") self.widgets.pwd_entry2.set_text("") response = dialog.run() if response == gtk.RESPONSE_OK: pwd1 = self.widgets.pwd_entry1.get_text() pwd2 = self.widgets.pwd_entry2.get_text() user = self.get_selected_user() if pwd1 == "" or pwd2 == "": msg = _("The password for user <b>%s</b> has not been " "changed.") % user utils.message_dialog(msg, gtk.MESSAGE_WARNING, parent=self.get_window()) return elif pwd1 != pwd2: msg = _("The passwords do not match. The password for " "user <b>%s</b> has not been changed.") % user utils.message_dialog(msg, gtk.MESSAGE_WARNING, parent=self.get_window()) return else: try: set_password(pwd1, user) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window())
def on_pwd_button_clicked(self, button, *args): dialog = self.widgets.pwd_dialog dialog.set_transient_for(self.get_window()) def _on_something(d, *args): d.hide() return True self.connect(dialog, 'delete-event', _on_something) self.connect(dialog, 'close', _on_something) self.connect(dialog, 'response', _on_something) self.widgets.pwd_entry1.set_text('') self.widgets.pwd_entry2.set_text('') response = dialog.run() if response == gtk.RESPONSE_OK: pwd1 = self.widgets.pwd_entry1.get_text() pwd2 = self.widgets.pwd_entry2.get_text() user = self.get_selected_user() if pwd1 == '' or pwd2 == '': msg = _('The password for user <b>%s</b> has not been ' 'changed.') % user utils.message_dialog(msg, gtk.MESSAGE_WARNING, parent=self.get_window()) return elif pwd1 != pwd2: msg = _('The passwords do not match. The password for ' 'user <b>%s</b> has not been changed.') % user utils.message_dialog(msg, gtk.MESSAGE_WARNING, parent=self.get_window()) return else: try: set_password(pwd1, user) except Exception, e: utils.message_dialog(utils.utf8(e), gtk.MESSAGE_ERROR, parent=self.get_window())
def on_new_button_clicked(self, *args): # TODO: don't set the OK button as sensitive in the name dialog # if the name already exists # TOD0: make "Enter" in the entry fire the default response d = gtk.Dialog(_("Formatter Name"), self.view.dialog, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) d.vbox.set_spacing(10) d.set_default_response(gtk.RESPONSE_ACCEPT) text = '<b>%s</b>' % _('Enter a name for the new formatter') label = gtk.Label() label.set_markup(text) label.set_padding(10, 10) d.vbox.pack_start(label) entry = gtk.Entry() entry.set_activates_default(True) d.vbox.pack_start(entry) d.show_all() names_model = self.view.widgets.names_combo.get_model() while True: if d.run() == gtk.RESPONSE_ACCEPT: name = entry.get_text() if name == '': continue elif names_model is not None \ and utils.tree_model_has(names_model, name): utils.message_dialog(_('%s already exists') % name) continue else: self.set_prefs_for(entry.get_text(), None, {}) self.populate_names_combo() utils.combo_set_active_text(self.view.widgets.names_combo, name) break else: break d.destroy()
def on_new_button_clicked(self, *args): # TODO: don't set the OK button as sensitive in the name dialog # if the name already exists # TOD0: make "Enter" in the entry fire the default response d = gtk.Dialog(_("Formatter Name"), self.view.dialog, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) d.vbox.set_spacing(10) d.set_default_response(gtk.RESPONSE_ACCEPT) text = '<b>%s</b>' % _('Enter a name for the new formatter') label = gtk.Label() label.set_markup(text) label.set_padding(10, 10) d.vbox.pack_start(label) entry = gtk.Entry() entry.set_activates_default(True) d.vbox.pack_start(entry) d.show_all() names_model = self.view.widgets.names_combo.get_model() while True: if d.run() == gtk.RESPONSE_ACCEPT: name = entry.get_text() if name == '': continue elif names_model is not None \ and utils.tree_model_has(names_model, name): utils.message_dialog(_('%s already exists') % name) continue else: self.set_prefs_for(entry.get_text(), None, {}) self.populate_names_combo() utils.combo_set_active_text(self.view.widgets.names_combo, name) break else: break d.destroy()
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
def command_handler(cmd, arg): """ Call a command handler. :param cmd: The name of the command to call :type cmd: str :param arg: The arg to pass to the command handler :type arg: list """ logger.debug('entering ui.command_handler %s %s' % (cmd, arg)) import gtk import bauble.utils as utils import bauble.pluginmgr as pluginmgr global last_handler handler_cls = None try: handler_cls = pluginmgr.commands[cmd] except KeyError, e: if cmd is None: utils.message_dialog(_('No default handler registered')) else: utils.message_dialog(_('No command handler for %s') % cmd) return
def command_handler(cmd, arg): """ Call a command handler. :param cmd: The name of the command to call :type cmd: str :param arg: The arg to pass to the command handler :type arg: list """ import gtk from bauble.utils.log import error import bauble.utils as utils import bauble.pluginmgr as pluginmgr global last_handler handler_cls = None try: handler_cls = pluginmgr.commands[cmd] except KeyError, e: if cmd is None: utils.message_dialog(_('No default handler registered')) else: utils.message_dialog(_('No command handler for %s' % cmd)) return
def verify_connection(engine, show_error_dialogs=False): """ Test whether a connection to an engine is a valid Ghini 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 Ghini') 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 Ghini.') utils.message_dialog(msg, gtk.MESSAGE_ERROR) raise except error.VersionError, e: msg = (_('You are using Ghini 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
traceback.format_exc(), gtk.MESSAGE_ERROR) # register the plugin commands seperately from the plugin initialization for plugin in ordered: if plugin.commands in (None, []): continue for cmd in plugin.commands: try: register_command(cmd) except Exception, e: logger.debug("exception %s while registering command %s" % (e, cmd)) msg = 'Error: Could not register command handler.\n\n%s' % \ utils.xml_safe(str(e)) utils.message_dialog(msg, gtk.MESSAGE_ERROR) # don't build the tools menu if we're running from the tests and # we don't have a gui if bauble.gui: bauble.gui.build_tools_menu() def install(plugins_to_install, import_defaults=True, force=False): """ :param plugins_to_install: A list of plugins to install. If the string "all" is passed then install all plugins listed in the bauble.pluginmgr.plugins dict that aren't already listed in the plugin registry. :param import_defaults: Flag passed to the plugin's install()
def format(objs, **kwargs): # debug('format(%s)' % kwargs) stylesheet = kwargs['stylesheet'] authors = kwargs['authors'] renderer = kwargs['renderer'] source_type = kwargs['source_type'] use_private = kwargs['private'] error_msg = None if not stylesheet: error_msg = _('Please select a stylesheet.') elif not renderer: error_msg = _('Please select a a renderer') if error_msg is not None: utils.message_dialog(error_msg, gtk.MESSAGE_WARNING) return False fo_cmd = renderers_map[renderer] exe = fo_cmd.split(' ')[0] if not on_path(exe): utils.message_dialog( _('Could not find the command "%(exe)s" to ' 'start the %(renderer_name)s ' 'renderer.') % ({ 'exe': exe, 'renderer_name': renderer }), gtk.MESSAGE_ERROR) return False session = db.Session() # convert objects to ABCDAdapters depending on source type for # passing to create_abcd adapted = [] if source_type == plant_source_type: plants = sorted(get_plants_pertinent_to(objs, session=session), key=utils.natsort_key) if len(plants) == 0: utils.message_dialog( _('There are no plants in the search ' 'results. Please try another search.')) return False for p in plants: if use_private: adapted.append(PlantABCDAdapter(p, for_labels=True)) elif not p.accession.private: adapted.append(PlantABCDAdapter(p, for_labels=True)) elif source_type == species_source_type: species = sorted(get_species_pertinent_to(objs, session=session), key=utils.natsort_key) if len(species) == 0: utils.message_dialog( _('There are no species in the search ' 'results. Please try another search.')) return False for s in species: adapted.append(SpeciesABCDAdapter(s, for_labels=True)) elif source_type == accession_source_type: accessions = sorted(get_accessions_pertinent_to(objs, session=session), key=utils.natsort_key) if len(accessions) == 0: utils.message_dialog( _('There are no accessions in the search ' 'results. Please try another search.')) return False for a in accessions: if use_private: adapted.append(AccessionABCDAdapter(a, for_labels=True)) elif not a.private: adapted.append(AccessionABCDAdapter(a, for_labels=True)) else: raise NotImplementedError('unknown source type') if len(adapted) == 0: # nothing adapted....possibly everything was private # TODO: if everything was private and that is really why we got # here then it is probably better to show a dialog with a message # and raise and exception which appears as an error raise Exception('No objects could be adapted to ABCD units.') abcd_data = create_abcd(adapted, authors=authors, validate=False) session.close() logger.debug(etree.dump(abcd_data.getroot())) # create xsl fo file dummy, fo_filename = tempfile.mkstemp() style_etree = etree.parse(stylesheet) transform = etree.XSLT(style_etree) result = transform(abcd_data) fo_outfile = open(fo_filename, 'w') fo_outfile.write(str(result)) fo_outfile.close() dummy, filename = tempfile.mkstemp() filename = '%s.pdf' % filename # TODO: checkout pyexpect for spawning processes # run the report to produce the pdf file, the command has to be # on the path for this to work fo_cmd = fo_cmd % ({ 'fo_filename': fo_filename, 'out_filename': filename }) logger.debug(fo_cmd) # TODO: use popen to get output os.system(fo_cmd) logger.debug(filename) if not os.path.exists(filename): utils.message_dialog( _('Error creating the PDF file. Please ' 'ensure that your PDF formatter is ' 'properly installed.'), gtk.MESSAGE_ERROR) return False else: 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 True
# TODO: use popen to get output os.system(fo_cmd) logger.debug(filename) if not os.path.exists(filename): utils.message_dialog( _('Error creating the PDF file. Please ' 'ensure that your PDF formatter is ' 'properly installed.'), gtk.MESSAGE_ERROR) return False else: 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 True # expose the formatter try: import lxml.etree as etree except ImportError: utils.message_dialog('The <i>lxml</i> package is required for the ' 'XSL report plugin') else: formatter_plugin = XSLFormatterPlugin
display = gtk.gdk.display_get_default() if display is None: print _("**Error: Bauble must be run in a windowed environment.") sys.exit(1) import bauble.pluginmgr as pluginmgr import bauble.utils as utils # initialize threading gobject.threads_init() try: import bauble.db as db except Exception, e: utils.message_dialog(utils.xml_safe(e), gtk.MESSAGE_ERROR) sys.exit(1) # declare module level variables global gui, default_icon, conn_name default_icon = os.path.join(paths.lib_dir(), "images", "icon.svg") open_exc = None # open default database if uri is None: from bauble.connmgr import start_connection_manager while True: if not uri or not conn_name: conn_name, uri = start_connection_manager() if conn_name is None:
class CSVImporter(Importer): """imports comma separated value files into a Bauble database. It imports multiple files, each of them equally named as the bauble database tables. The bauble tables dependency graph defines the correct import order, each file being imported will completely replace any existing data in the corresponding table. The CSVImporter imports the rows of the CSV file in chunks rather than one row at a time. The non-server side column defaults are determined before the INSERT statement is generated instead of getting new defaults for each row. This shouldn't be a problem but it also means that your column default should change depending on the value of previously inserted rows. """ def __init__(self): super(CSVImporter, self).__init__() self.__error = False # flag to indicate error on import self.__cancel = False # flag to cancel importing self.__pause = False # flag to pause importing self.__error_exc = False def start(self, filenames=None, metadata=None, force=False): '''start the import process. this is a non blocking method: we queue the process as a bauble task. there is no callback informing whether it is successfully completed or not. ''' if metadata is None: metadata = db.metadata # use the default metadata if filenames is None: filenames = self._get_filenames() if filenames is None: return bauble.task.queue(self.run(filenames, metadata, force)) @staticmethod def _toposort_file(filename, key_pairs): """ filename: the csv file to sort key_pairs: tuples of the form (parent, child) where for each line in the file the line[parent] needs to be sorted before any of the line[child]. parent is usually the name of the foreign_key column and child is usually the column that the foreign key points to, e.g ('parent_id', 'id') """ f = open(filename, 'rb') reader = UnicodeReader(f, quotechar=QUOTE_CHAR, quoting=QUOTE_STYLE) # create a dictionary of the lines mapped to the child field bychild = {} for line in reader: for parent, child in key_pairs: bychild[line[child]] = line f.close() fields = reader.reader.fieldnames del reader # create pairs from the values in the lines where pair[0] # should come before pair[1] when the lines are sorted pairs = [] for line in bychild.values(): for parent, child in key_pairs: if line[parent] and line[child]: pairs.append((line[parent], line[child])) # sort the keys and flatten the lines back into a list sorted_keys = utils.topological_sort(bychild.keys(), pairs) sorted_lines = [] for key in sorted_keys: sorted_lines.append(bychild[key]) # write a temporary file of the sorted lines import tempfile tmppath = tempfile.mkdtemp() head, tail = os.path.split(filename) filename = os.path.join(tmppath, tail) tmpfile = open(filename, 'wb') tmpfile.write('%s\n' % ','.join(fields)) #writer = UnicodeWriter(tmpfile, fields, quotechar=QUOTE_CHAR, writer = csv.DictWriter(tmpfile, fields, quotechar=QUOTE_CHAR, quoting=QUOTE_STYLE) writer.writerows(sorted_lines) tmpfile.flush() tmpfile.close() del writer return filename 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 # create a mapping of table names to filenames filename_dict = {} for f in filenames: path, base = os.path.split(f) table_name, ext = os.path.splitext(base) if table_name in filename_dict: safe = utils.xml_safe values = dict(table_name=safe(table_name), file_name=safe(filename_dict[table_name]), file_name2=safe(f)) msg = _('More than one file given to import into table ' '<b>%(table_name)s</b>: %(file_name)s, ' '(file_name2)s') % values utils.message_dialog(msg, gtk.MESSAGE_ERROR) return filename_dict[table_name] = f # resolve filenames to table names and return them in sorted order sorted_tables = [] for table in metadata.sorted_tables: try: sorted_tables.insert(0, (table, filename_dict.pop(table.name))) except KeyError, e: # table.name not in list of filenames pass
command = 'exxml' def __call__(self, cmd, arg): logger.debug('XMLExportCommandHandler(%s)' % arg) exporter = XMLExporter() logger.debug('starting') exporter.start(arg) logger.debug('started') class XMLExportTool(pluginmgr.Tool): category = _("Export") label = _("XML") @classmethod def start(cls): c = XMLExporter() c.start() class XMLImexPlugin(pluginmgr.Plugin): tools = [XMLExportTool] commands = [XMLExportCommandHandler] try: import lxml.etree as etree except ImportError: utils.message_dialog('The <i>lxml</i> package is required for the ' 'XML Import/Exporter plugin')