From de7ae6b763e48607f7d1da8f4f98bd7386cccba8 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Tue, 11 Aug 2009 15:36:23 +0200 Subject: GUI: Added option to disable/enable plugins (config preview) --- lib/Plugins/Bugzilla.GTKBuilder | 17 +-- lib/Plugins/KerneloopsReporter.GTKBuilder | 10 +- lib/Plugins/Logger.GTKBuilder | 10 +- lib/Plugins/Mailx.GTKBuilder | 10 +- src/Gui/ABRTPlugin.py | 52 ++++++++ src/Gui/CCDBusBackend.py | 43 +++--- src/Gui/CCDump.py | 2 +- src/Gui/CCMainWindow.py | 7 + src/Gui/Makefile.am | 7 +- src/Gui/PluginList.py | 51 +++++++ src/Gui/PluginSettingsUI.py | 57 ++++++++ src/Gui/SettingsDialog.py | 133 ++++++++++++++++++ src/Gui/ccgui.glade | 19 +++ src/Gui/settings.GtkBuilder | 215 ++++++++++++++++++++++++++++++ 14 files changed, 579 insertions(+), 54 deletions(-) create mode 100644 src/Gui/ABRTPlugin.py create mode 100644 src/Gui/PluginList.py create mode 100644 src/Gui/PluginSettingsUI.py create mode 100644 src/Gui/SettingsDialog.py create mode 100644 src/Gui/settings.GtkBuilder diff --git a/lib/Plugins/Bugzilla.GTKBuilder b/lib/Plugins/Bugzilla.GTKBuilder index 6d3bb4c3..2c2d63ca 100644 --- a/lib/Plugins/Bugzilla.GTKBuilder +++ b/lib/Plugins/Bugzilla.GTKBuilder @@ -1,13 +1,13 @@ - + - + 5 normal False - + True vertical 2 @@ -19,10 +19,6 @@ True Bugzilla plugin configuration - - bold - 1.300000 - 0 @@ -60,7 +56,7 @@ - + True True @@ -124,7 +120,7 @@ True end - + gtk-apply True True @@ -161,8 +157,9 @@ - button1 + bApply button2 + diff --git a/lib/Plugins/KerneloopsReporter.GTKBuilder b/lib/Plugins/KerneloopsReporter.GTKBuilder index 69400f19..74cb36b9 100644 --- a/lib/Plugins/KerneloopsReporter.GTKBuilder +++ b/lib/Plugins/KerneloopsReporter.GTKBuilder @@ -1,13 +1,13 @@ - + - + 5 normal False - + True vertical 2 @@ -19,10 +19,6 @@ True Kerneloops Reporter plugin configuration - - bold - 1.300000 - 0 diff --git a/lib/Plugins/Logger.GTKBuilder b/lib/Plugins/Logger.GTKBuilder index b64d40ae..a6b82c00 100644 --- a/lib/Plugins/Logger.GTKBuilder +++ b/lib/Plugins/Logger.GTKBuilder @@ -1,13 +1,13 @@ - + - + 5 normal False - + True vertical 2 @@ -19,10 +19,6 @@ True Logger plugin configuration - - bold - 1.300000 - 0 diff --git a/lib/Plugins/Mailx.GTKBuilder b/lib/Plugins/Mailx.GTKBuilder index 62cc0d4b..df359734 100644 --- a/lib/Plugins/Mailx.GTKBuilder +++ b/lib/Plugins/Mailx.GTKBuilder @@ -1,13 +1,13 @@ - + - + 5 normal False - + True vertical 2 @@ -19,10 +19,6 @@ True Mailx plugin configuration - - bold - 1.300000 - 0 diff --git a/src/Gui/ABRTPlugin.py b/src/Gui/ABRTPlugin.py new file mode 100644 index 00000000..ff6478be --- /dev/null +++ b/src/Gui/ABRTPlugin.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +""" PluginInfo keys: +WWW +Name +Enabled +GTKBuilder +Version +Type +Email +Description +""" + + +class PluginSettings(dict): + def __init__(self): + print "Init plugin settings" + + def __init__(self, settings_dict): + for key in settings_dict.keys(): + self[key] = settings_dict[key] + +"""Class to represent common plugin info""" +class PluginInfo(): + keys = ["WWW", "Name", "Enabled", + "GTKBuilder", "Version", + "Type", "Email", "Description"] + + def __init__(self): + #print "Init PluginInfo" + self.WWW = None + self.Name = None + self.Enabled = None + self.GTKBuilder = None + self.Version = None + self.Type = None + self.Email = None + self.Description = None + self.Settings = None + + def getName(self): + return self.Name + + def getDescription(self): + return self.Description + + def getGUI(self): + return self.GTKBuilder + + def __str__(self): + return self.Name + diff --git a/src/Gui/CCDBusBackend.py b/src/Gui/CCDBusBackend.py index 52e7bdaa..6fe13576 100644 --- a/src/Gui/CCDBusBackend.py +++ b/src/Gui/CCDBusBackend.py @@ -35,28 +35,20 @@ class DBusManager(gobject.GObject): try: session = dbus.SessionBus() except Exception, e: - print e - - try: - app_proxy = session.get_object(APP_NAME,APP_PATH) - app_iface = dbus.Interface(app_proxy, dbus_interface=APP_IFACE) - # app is running, so make it show it self - app_iface.show() - raise ABRTExceptions.IsRunning() - except DBusException, e: - # cannot create proxy or call the method => gui is not running + # probably run after "$ su" pass - """ - try: - session = dbus.SessionBus() - except: - # FIXME: root doesn't have SessionBus - pass if session: - if session.request_name(APP_NAME, dbus.bus.NAME_FLAG_DO_NOT_QUEUE) != dbus.bus.REQUEST_NAME_REPLY_PRIMARY_OWNER: - raise Exception("Name %s is taken,\nanother instance is already running." % APP_NAME) - """ + try: + app_proxy = session.get_object(APP_NAME,APP_PATH) + app_iface = dbus.Interface(app_proxy, dbus_interface=APP_IFACE) + # app is running, so make it show it self + app_iface.show() + raise ABRTExceptions.IsRunning() + except DBusException, e: + # cannot create proxy or call the method => gui is not running + pass + gobject.GObject.__init__(self) # signal emited when new crash is detected gobject.signal_new ("crash", self ,gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,()) @@ -189,3 +181,16 @@ class DBusManager(gobject.GObject): row_dict[column] = row[column] rows.append(row_dict); return rows + + def getPluginsInfo(self): + return self.cc.GetPluginsInfo() + + def getPluginSettings(self, plugin_name): + return self.cc.GetPluginSettings(plugin_name) + + def registerPlugin(self, plugin_name): + return self.cc.RegisterPlugin(plugin_name) + + def unRegisterPlugin(self, plugin_name): + return self.cc.UnRegisterPlugin(plugin_name) + diff --git a/src/Gui/CCDump.py b/src/Gui/CCDump.py index 04bca621..0c7b29c0 100644 --- a/src/Gui/CCDump.py +++ b/src/Gui/CCDump.py @@ -6,7 +6,7 @@ EDITABLE = 1 CONTENT = 2 class Dump(): - """Class for mapping the debug dump to pyhon object""" + """Class for mapping the debug dump to python object""" def __init__(self): self.UUID = None self.UID = None diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index 8ddaa517..4b5fed2a 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -11,6 +11,7 @@ import CCDBusBackend from CC_gui_functions import * from CCDumpList import getDumpList, DumpList from CCReporterDialog import ReporterDialog +from SettingsDialog import SettingsDialog from CCReport import Report from exception import installExceptionHandler, handleMyException import ABRTExceptions @@ -100,6 +101,7 @@ class MainWindow(): self.wTree.get_widget("bReport").connect("clicked", self.on_bReport_clicked) self.wTree.get_widget("miQuit").connect("activate", self.on_bQuit_clicked) self.wTree.get_widget("miAbout").connect("activate", self.on_miAbout_clicked) + self.wTree.get_widget("miPreferences").connect("activate", self.on_miPreferences_clicked) # connect handlers for daemon signals self.ccdaemon.connect("crash", self.on_data_changed_cb, None) self.ccdaemon.connect("analyze-complete", self.on_analyze_complete_cb, self.pBarWindow) @@ -121,6 +123,11 @@ class MainWindow(): dialog = self.wTree.get_widget("about") result = dialog.run() dialog.hide() + + def on_miPreferences_clicked(self, widget): + dialog = SettingsDialog(self.window,self.ccdaemon) + dialog.hydrate() + dialog.show() def error_cb(self, daemon, message=None): # try to hide the progressbar, we dont really care if it was visible .. diff --git a/src/Gui/Makefile.am b/src/Gui/Makefile.am index 1715588a..ca8a790f 100644 --- a/src/Gui/Makefile.am +++ b/src/Gui/Makefile.am @@ -3,10 +3,11 @@ bin_SCRIPTS = abrt-gui PYTHON_FILES = CCDBusBackend.py CCDumpList.py CCDump.py CC_gui_functions.py \ - ccgui.glade report.glade CCReporterDialog.py CCReport.py \ - CCMainWindow.py exception.py CellRenderers.py ABRTExceptions.py + CCReporterDialog.py CCReport.py \ + CCMainWindow.py exception.py CellRenderers.py ABRTExceptions.py \ + SettingsDialog.py ABRTPlugin.py PluginList.py PluginSettingsUI.py -GLADE_FILES = ccgui.glade report.glade +GLADE_FILES = ccgui.glade report.glade settings.GtkBuilder EXTRA_DIST = $(PYTHON_FILES) $(GLADE_FILES) abrt-gui abrt.desktop diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py new file mode 100644 index 00000000..b315eb95 --- /dev/null +++ b/src/Gui/PluginList.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +import CCDBusBackend +from ABRTPlugin import PluginInfo, PluginSettings + +class PluginInfoList(list): + """Class to store list of PluginInfos""" + def __init__(self,dbus_manager=None): + self.dm = dbus_manager + self.ddict = {} + + def load(self): + if self.dm: + #print "loading PluginList" + try: + rows = self.dm.getPluginsInfo() + #print rows + for row in rows: + entry = PluginInfo() + for column in row: + #print "PluginInfoList adding %s:%s" % (column,row[column]) + entry.__dict__[column] = row[column] + if entry.Enabled == "yes": + #print ">>%s<<" % entry + entry.Settings = PluginSettings(self.dm.getPluginSettings(str(entry))) + #for i in entry.Settings.keys(): + # print "%s: %s" % (i, entry.Settings[i]) + #else: + # print "%s is disabled" % entry + self.append(entry) + self.ddict[entry.getName()] = entry + except Exception, e: + print e + return + else: + print "db == None!" + + +__PFList = None +__PFList_dbmanager = None + +def getPluginInfoList(dbmanager,refresh=None): + global __PFList + global __PFList_dbmanager + + if __PFList == None or refresh or __PFList_dbmanager != dbmanager: + __PFList = PluginInfoList(dbus_manager=dbmanager) + __PFList.load() + __PFList_dbmanager = dbmanager + return __PFList + +__PFList = None diff --git a/src/Gui/PluginSettingsUI.py b/src/Gui/PluginSettingsUI.py new file mode 100644 index 00000000..55174d6e --- /dev/null +++ b/src/Gui/PluginSettingsUI.py @@ -0,0 +1,57 @@ +import gtk + +class PluginSettingsUI(gtk.Dialog): + def __init__(self, pluginfo): + #print "Init PluginSettingsUI" + gtk.Dialog.__init__(self) + self.plugin_name = pluginfo.Name + self.Settings = pluginfo.Settings + self.pluginfo = pluginfo + self.plugin_gui = None + + if pluginfo.getGUI(): + self.plugin_gui = gtk.Builder() + self.plugin_gui.add_from_file(pluginfo.getGUI()) + self.dialog = self.plugin_gui.get_object("PluginDialog") + if not self.dialog: + raise Exception("Can't find PluginDialog widget in UI description!") + self.dialog.set_title("%s" % pluginfo.getName()) + else: + # we shouldn't get here, but just to be safe + no_ui_label = gtk.Label("No UI for plugin %s" % pluginfo) + self.add(no_ui_label) + no_ui_label.show() + + def hydrate(self): + if self.plugin_gui: + if self.pluginfo.Enabled == "yes": + if self.Settings: + #print "Hydrating %s" % self.plugin_name + for key,value in self.Settings.iteritems(): + #print "%s:%s" % (key,value) + widget = self.plugin_gui.get_object("conf_%s" % key) + if type(widget) == gtk.Entry: + widget.set_text(value) + elif type(widget) == gtk.CheckButton: + widget.set_active(value == "yes") + elif type(widget) == gtk.ComboBox: + print "combo box is not implemented" + else: + #print "Plugin %s has no configuration." % self.plugin_name + pass + else: + #print "Plugin %s is disabled." % self.plugin_name + pass + + else: + print "Nothing to hydrate!" + + def dehydrate(self): + #print "dehydrating %s" % self.pluginfo.getName() + pass + + def destroy(self): + self.dialog.destroy() + + def run(self): + return self.dialog.run() diff --git a/src/Gui/SettingsDialog.py b/src/Gui/SettingsDialog.py new file mode 100644 index 00000000..bd87a30c --- /dev/null +++ b/src/Gui/SettingsDialog.py @@ -0,0 +1,133 @@ +import sys +import gtk +from PluginList import getPluginInfoList, PluginInfoList +from CC_gui_functions import * +from PluginSettingsUI import PluginSettingsUI +from ABRTPlugin import PluginSettings + +class SettingsDialog: + def __init__(self, parent, daemon): + #print "Settings dialog init" + self.ccdaemon = daemon + self.builder = gtk.Builder() + builderfile = "%s%ssettings.GtkBuilder" % (sys.path[0],"/") + #print builderfile + try: + self.builder.add_from_file(builderfile) + except Exception, e: + print e + self.window = self.builder.get_object("wSettings") + if not self.window: + raise Exception("Can't load gui description for SettingsDialog!") + #self.window.set_parent(parent) + + self.pluginlist = self.builder.get_object("tvSettings") + self.pluginsListStore = gtk.ListStore(str, bool, object) + # set filter + self.modelfilter = self.pluginsListStore.filter_new() + self.modelfilter.set_visible_func(self.filter_plugins, None) + self.pluginlist.set_model(self.modelfilter) + # =============================================== + columns = [None]*1 + columns[0] = gtk.TreeViewColumn('Plugins') + + # create list + for column in columns: + n = self.pluginlist.append_column(column) + column.cell = gtk.CellRendererText() + column.pack_start(column.cell, False) + column.set_attributes(column.cell, text=(n-1)) + column.set_resizable(True) + + # toggle + toggle_renderer = gtk.CellRendererToggle() + toggle_renderer.set_property('activatable', True) + toggle_renderer.connect( 'toggled', self.on_enabled_toggled, self.pluginsListStore ) + column = gtk.TreeViewColumn('Enabled', toggle_renderer) + column.add_attribute( toggle_renderer, "active", 1) + self.pluginlist.insert_column(column, 0) + + #connect signals + self.pluginlist.connect("cursor-changed", self.on_tvDumps_cursor_changed) + self.builder.get_object("bConfigurePlugin").connect("clicked", self.on_bConfigurePlugin_clicked, self.pluginlist) + self.builder.get_object("bClose").connect("clicked", self.on_bClose_clicked) + + def on_enabled_toggled(self,cell, path, model): + plugin = model[path][model.get_n_columns()-1] + if model[path][1]: + #print "self.ccdaemon.UnRegisterPlugin(%s)" % (plugin.getName()) + self.ccdaemon.unRegisterPlugin(plugin.getName()) + # FIXME: create class plugin and move this into method Plugin.Enable() + plugin.Enabled = "no" + plugin.Settings = None + else: + #print "self.ccdaemon.RegisterPlugin(%s)" % (model[path][model.get_n_columns()-1]) + self.ccdaemon.registerPlugin(plugin.getName()) + # FIXME: create class plugin and move this into method Plugin.Enable() + plugin.Enabled = "yes" + plugin.Settings = PluginSettings(self.ccdaemon.getPluginSettings(plugin.getName())) + model[path][1] = not model[path][1] + + def filter_plugins(self, model, miter, data): + return True + def hydrate(self): + #print "settings hydrate" + self.pluginsListStore.clear() + try: + pluginlist = getPluginInfoList(self.ccdaemon, refresh=True) + except Exception, e: + print e + #gui_error_message("Error while loading plugins info, please check if abrt daemon is running\n %s" % e) + for entry in pluginlist: + n = self.pluginsListStore.append(["%s\n%s" % (entry.getName(), entry.Description), entry.Enabled == "yes", entry]) + + def dehydrate(self): + # we have nothing to save, plugin's does the work + pass + + def show(self): + self.window.show() + #if result == gtk.RESPONSE_APPLY: + # self.dehydrate() + #self.window.destroy() + #return result + + def on_bConfigurePlugin_clicked(self, button, pluginview): + pluginsListStore, path = pluginview.get_selection().get_selected_rows() + if not path: + self.builder.get_object("lDescription").set_label("ARGH...") + return + # this should work until we keep the row object in the last position + pluginfo = pluginsListStore.get_value(pluginsListStore.get_iter(path[0]), pluginsListStore.get_n_columns()-1) + try: + ui = PluginSettingsUI(pluginfo) + except Exception, e: + gui_error_message("Error while opening plugin settings UI: \n\n%s" % e) + return + ui.hydrate() + response = ui.run() + if response == gtk.RESPONSE_APPLY: + ui.dehydrate() + elif response == gtk.RESPONSE_CANCEL: + pass + else: + print "unknown response from settings dialog" + ui.destroy() + + def on_bClose_clicked(self, button): + self.window.destroy() + + def on_tvDumps_cursor_changed(self, treeview): + pluginsListStore, path = treeview.get_selection().get_selected_rows() + if not path: + self.builder.get_object("lDescription").set_label("ARGH...") + return + # this should work until we keep the row object in the last position + pluginfo = pluginsListStore.get_value(pluginsListStore.get_iter(path[0]), pluginsListStore.get_n_columns()-1) + self.builder.get_object("lPluginAuthor").set_text(pluginfo.Email) + self.builder.get_object("lPluginVersion").set_text(pluginfo.Version) + self.builder.get_object("lPluginWebSite").set_text(pluginfo.WWW) + self.builder.get_object("lPluginName").set_text(pluginfo.Name) + self.builder.get_object("lPluginDescription").set_text(pluginfo.Description) +# print (pluginfo.Enabled == "yes" and pluginfo.GTKBuilder != "") + self.builder.get_object("bConfigurePlugin").set_sensitive(pluginfo.Enabled == "yes" and pluginfo.GTKBuilder != "") diff --git a/src/Gui/ccgui.glade b/src/Gui/ccgui.glade index 53da45b6..958af5d9 100644 --- a/src/Gui/ccgui.glade +++ b/src/Gui/ccgui.glade @@ -31,6 +31,25 @@ + + + True + _Edit + True + + + True + + + gtk-preferences + True + True + + + + + + True diff --git a/src/Gui/settings.GtkBuilder b/src/Gui/settings.GtkBuilder new file mode 100644 index 00000000..422b6231 --- /dev/null +++ b/src/Gui/settings.GtkBuilder @@ -0,0 +1,215 @@ + + + + + + Settings + True + 450 + 400 + + + True + vertical + + + + + + True + True + never + automatic + + + True + True + + + + + 1 + + + + + True + True + + + True + vertical + + + True + 0.05000000074505806 + label + + + 0 + + + + + True + label + + + 1 + + + + + True + 3 + 3 + True + + + True + 0.05000000074505806 + Web Site: + + + 2 + 3 + + + + + True + 0.05000000074505806 + Author: + + + 1 + 2 + GTK_FILL + + + + + True + 0.05000000074505806 + Version: + + + GTK_FILL + + + + + True + 0.05000000074505806 + label + + + 1 + 3 + + + + + True + 0.05000000074505806 + label + + + 1 + 3 + 1 + 2 + + + + + True + 0.05000000074505806 + label + + + 1 + 3 + 2 + 3 + + + + + 2 + + + + + + + True + Plugin Details + + + + + False + False + 2 + + + + + True + 11 + + + True + + + + + + 0 + + + + + C_onfigure plugin + True + True + True + True + + + 1 + + + + + gtk-close + True + True + True + True + + + 2 + + + + + False + 3 + + + + + True + 2 + + + False + 4 + + + + + + -- cgit