diff options
| author | Jiri Moskovcak <jmoskovc@redhat.com> | 2009-02-23 16:37:25 +0100 |
|---|---|---|
| committer | Jiri Moskovcak <jmoskovc@redhat.com> | 2009-02-23 16:37:25 +0100 |
| commit | d740acb4e7c11eaf5deb94b35f33f0bfb7ee99be (patch) | |
| tree | 3232e0a7820ea3963c75975a98c1f2eebc061fad /src | |
| parent | 79833fc32cf10ef409b2be63fa58b4f8dfbe1e06 (diff) | |
| download | abrt-d740acb4e7c11eaf5deb94b35f33f0bfb7ee99be.tar.gz abrt-d740acb4e7c11eaf5deb94b35f33f0bfb7ee99be.tar.xz abrt-d740acb4e7c11eaf5deb94b35f33f0bfb7ee99be.zip | |
Added more functionality to gui
Diffstat (limited to 'src')
| -rw-r--r-- | src/Gui/CCDBusBackend.py (renamed from src/Gui/CCGuiDbusBackend.py) | 19 | ||||
| -rw-r--r-- | src/Gui/CCDump.py | 35 | ||||
| -rw-r--r-- | src/Gui/CCDumpList.py | 41 | ||||
| -rw-r--r-- | src/Gui/CCReporterDialog.py | 56 | ||||
| -rw-r--r-- | src/Gui/CC_gui_functions.py | 39 | ||||
| -rw-r--r-- | src/Gui/ccgui.glade | 108 | ||||
| -rwxr-xr-x | src/Gui/mainwindow.py | 84 |
7 files changed, 296 insertions, 86 deletions
diff --git a/src/Gui/CCGuiDbusBackend.py b/src/Gui/CCDBusBackend.py index 406c1bf..ad3e82c 100644 --- a/src/Gui/CCGuiDbusBackend.py +++ b/src/Gui/CCDBusBackend.py @@ -14,10 +14,12 @@ class DBusManager(gobject.GObject): # and later with policyKit def __init__(self): gobject.GObject.__init__(self) + # signal emited when new crash is detected + gobject.signal_new ("crash", self ,gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,()) # binds the dbus to glib mainloop DBusGMainLoop(set_as_default=True) self.proxy = None - self.connect() + self.connect_to_daemon() if self.proxy: self.cc = dbus.Interface(self.proxy, dbus_interface=CC_IFACE) #intr = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Introspectable') @@ -30,29 +32,28 @@ class DBusManager(gobject.GObject): print "disconnect" def crash_cb(self,*args): - print "got another crash while in gui!" - for arg in args: - print arg + #FIXME "got another crash, gui should reload!" + #for arg in args: + # print arg #emit a signal + #print "crash" + self.emit("crash") - def connect(self): + def connect_to_daemon(self): bus = dbus.SystemBus() if not bus: raise Exception("Can't connect to dbus") try: self.proxy = bus.get_object(CC_IFACE, CC_PATH) except Exception, e: - print "Error while creating the proxy" - print e + raise Exception(e.message + "\nPlease check if crash-catcher daemon is running.") def getDumps(self): row_dict = None rows = [] for row in self.cc.GetCrashInfosMap(""): -# print row row_dict = {} for column in row: row_dict[column] = row[column] - # print "%s:%s" % (column, row[column]) rows.append(row_dict); return rows diff --git a/src/Gui/CCDump.py b/src/Gui/CCDump.py new file mode 100644 index 0000000..87474e9 --- /dev/null +++ b/src/Gui/CCDump.py @@ -0,0 +1,35 @@ +from datetime import datetime + +class Dump(): + """Class for mapping the debug dump to pyhon object""" + def __init__(self): + self.UUID = None + self.UID = None + self.Count = None + self.Executable = None + self.Package = None + self.Time = None + + def getUUID(self): + return self.UUID + + def getUID(self): + return self.UID + + def getCount(self): + return self.Count + + def getExecutable(self): + return self.Executable + + def getPackage(self): + return self.Package + + def getTime(self,format): + #print format + if format: + try: + return datetime.fromtimestamp(int(self.Time)).strftime(format) + except Exception, e: + print e + return int(self.Time) diff --git a/src/Gui/CCDumpList.py b/src/Gui/CCDumpList.py new file mode 100644 index 0000000..25e12af --- /dev/null +++ b/src/Gui/CCDumpList.py @@ -0,0 +1,41 @@ +import CCDBusBackend +from CCDump import Dump + +class DumpList(list): + """Class to store list of debug dumps""" + def __init__(self,dbus_manager=None): + self.dm = dbus_manager + + def load(self): + if self.dm: + print "loading DumpList" + try: + rows = self.dm.getDumps() + #print rows + for row in rows: + entry = Dump() + for column in row: + #print "DumpList adding %s:%s" % (column,row[column]) + entry.__dict__[column] = row[column] + self.append(entry) + except Exception, e: + print e + return + else: + print "db == None!" + + +__PFList = None +__PFList_dbmanager = None + +def getDumpList(dbmanager,refresh=None): + global __PFList + global __PFList_dbmanager + + if __PFList == None or refresh or __PFList_dbmanager != dbmanager: + __PFList = DumpList(dbus_manager=dbmanager) + __PFList.load() + __PFList_dbmanager = dbmanager + return __PFList + +__PFList = None diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py new file mode 100644 index 0000000..c801de3 --- /dev/null +++ b/src/Gui/CCReporterDialog.py @@ -0,0 +1,56 @@ +import pygtk +pygtk.require("2.0") +import gtk +import gtk.glade +import sys +from CC_gui_functions import * +from CCDumpList import getDumpList, DumpList + +class ReporterDialog(): + """Reporter window""" + def __init__(self, dump): + self.dump = dump + #Set the Glade file + self.gladefile = "ccgui.glade" + self.wTree = gtk.glade.XML(self.gladefile) + #Get the Main Window, and connect the "destroy" event + self.window = self.wTree.get_widget("reporter_dialog") + + #init the dumps treeview + self.tvReport = self.wTree.get_widget("tvReport") + columns = [None]*2 + columns[0] = gtk.TreeViewColumn('Item') + columns[1] = gtk.TreeViewColumn('Value') + + self.reportListStore = gtk.ListStore(str, str, bool) + # set filter + #self.modelfilter = self.reportListStore.filter_new() + #self.modelfilter.set_visible_func(self.filter_dumps, None) + self.tvReport.set_model(self.reportListStore) + renderer = gtk.CellRendererText() + column = gtk.TreeViewColumn('Item', renderer, text=0) + self.tvReport.append_column(column) + + renderer = gtk.CellRendererText() + column = gtk.TreeViewColumn('Value', renderer, text=1, editable=2) + self.tvReport.append_column(column) + + + # connect the signals + self.wTree.get_widget("bApply").connect("clicked", self.on_apply_clicked, self.tvReport) + + self.hydrate() + + def on_apply_clicked(self, button, treeview): + #print treeview + self.window.hide() + + def hydrate(self): + for item in self.dump.__dict__: + self.reportListStore.append([item, self.dump.__dict__[item], False]) + self.reportListStore.append(["Comment","", True]) + + def run(self): + self.window.show() + + diff --git a/src/Gui/CC_gui_functions.py b/src/Gui/CC_gui_functions.py new file mode 100644 index 0000000..5ac8e8c --- /dev/null +++ b/src/Gui/CC_gui_functions.py @@ -0,0 +1,39 @@ +import gtk + +def gui_error_message ( message, parent_dialog=None, + message_type=gtk.MESSAGE_ERROR, + widget=None, page=0, broken_widget=None ): + + dialog = gtk.MessageDialog( parent_dialog, + gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, + message_type, gtk.BUTTONS_OK, + message ) + + if parent_dialog: + dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT) + dialog.set_transient_for(parent_dialog) + else: + dialog.set_position (gtk.WIN_POS_CENTER) + + ret = dialog.run () + dialog.destroy() + return ret + +def gui_info_dialog ( message, parent_dialog=None, + message_type=gtk.MESSAGE_INFO, + widget=None, page=0, broken_widget=None ): + + dialog = gtk.MessageDialog( parent_dialog, + gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, + message_type, gtk.BUTTONS_YES_NO, + message ) + + if parent_dialog: + dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT) + dialog.set_transient_for(parent_dialog) + else: + dialog.set_position (gtk.WIN_POS_CENTER) + + ret = dialog.run () + dialog.destroy() + return ret diff --git a/src/Gui/ccgui.glade b/src/Gui/ccgui.glade index 3623c15..61c2981 100644 --- a/src/Gui/ccgui.glade +++ b/src/Gui/ccgui.glade @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> -<!--Generated with glade3 3.4.5 on Fri Feb 20 16:42:05 2009 --> +<!--Generated with glade3 3.4.5 on Mon Feb 23 15:20:47 2009 --> <glade-interface> <widget class="GtkWindow" id="main_window"> <property name="default_width">640</property> @@ -336,7 +336,7 @@ </packing> </child> <child> - <widget class="GtkStatusbar" id="statusbar1"> + <widget class="GtkStatusbar" id="appBar"> <property name="visible">True</property> <property name="spacing">2</property> </widget> @@ -348,7 +348,7 @@ </widget> </child> </widget> - <widget class="GtkDialog" id="dialog1"> + <widget class="GtkDialog" id="reporter_dialog"> <property name="border_width">5</property> <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> <property name="default_width">400</property> @@ -365,14 +365,14 @@ <child> <widget class="GtkLabel" id="label10"> <property name="visible">True</property> - <property name="label" translatable="yes">label</property> + <property name="label" translatable="yes">Report</property> </widget> <packing> <property name="expand">False</property> </packing> </child> <child> - <widget class="GtkTreeView" id="treeview1"> + <widget class="GtkTreeView" id="tvReport"> <property name="visible">True</property> <property name="can_focus">True</property> </widget> @@ -390,7 +390,7 @@ <property name="visible">True</property> <property name="layout_style">GTK_BUTTONBOX_END</property> <child> - <widget class="GtkButton" id="button4"> + <widget class="GtkButton" id="bApply"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> @@ -400,7 +400,7 @@ </widget> </child> <child> - <widget class="GtkButton" id="button5"> + <widget class="GtkButton" id="bCancel"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> @@ -459,53 +459,6 @@ <placeholder/> </child> <child> - <widget class="GtkLabel" id="label14"> - <property name="visible">True</property> - <property name="label" translatable="yes">BlackList</property> - </widget> - </child> - <child> - <widget class="GtkEntry" id="entry1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label15"> - <property name="visible">True</property> - <property name="label" translatable="yes">Database Plugin</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="combobox1"> - <property name="visible">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label16"> - <property name="visible">True</property> - <property name="label" translatable="yes">OpenPGP Public Keys</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - </packing> - </child> - <child> <widget class="GtkHBox" id="hbox7"> <property name="visible">True</property> <child> @@ -553,6 +506,53 @@ <property name="bottom_attach">3</property> </packing> </child> + <child> + <widget class="GtkLabel" id="label16"> + <property name="visible">True</property> + <property name="label" translatable="yes">OpenPGP Public Keys</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="combobox1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="label" translatable="yes">Database Plugin</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkEntry" id="entry1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="label" translatable="yes">BlackList</property> + </widget> + </child> </widget> </child> <child> diff --git a/src/Gui/mainwindow.py b/src/Gui/mainwindow.py index 81d7385..b333379 100755 --- a/src/Gui/mainwindow.py +++ b/src/Gui/mainwindow.py @@ -5,17 +5,26 @@ import pygtk pygtk.require("2.0") import gtk import gtk.glade -import CCGuiDbusBackend -from datetime import datetime +import CCDBusBackend +import sys +from CC_gui_functions import * +from CCDumpList import getDumpList, DumpList +from CCReporterDialog import ReporterDialog def cb(self, *args): pass -class CCMainWindow(): +class MainWindow(): """This is an Hello World GTK application""" def __init__(self): - self.ccdaemon = CCGuiDbusBackend.DBusManager() + try: + self.ccdaemon = CCDBusBackend.DBusManager() + except Exception, e: + # show error message if connection fails + # FIXME add an option to start the daemon + gui_error_message(e.message) + sys.exit() #Set the Glade file self.gladefile = "ccgui.glade" self.wTree = gtk.glade.XML(self.gladefile) @@ -26,13 +35,15 @@ class CCMainWindow(): if (self.window): self.window.connect("destroy", gtk.main_quit) + self.appBar = self.wTree.get_widget("appBar") + #init the dumps treeview self.dlist = self.wTree.get_widget("tvDumps") columns = [None]*2 columns[0] = gtk.TreeViewColumn('Date') - columns[1] = gtk.TreeViewColumn('package') + columns[1] = gtk.TreeViewColumn('Package') # create list - self.dumpsListStore = gtk.ListStore(str, str, int) + self.dumpsListStore = gtk.ListStore(str, str, object) # set filter self.modelfilter = self.dumpsListStore.filter_new() self.modelfilter.set_visible_func(self.filter_dumps, None) @@ -49,7 +60,29 @@ class CCMainWindow(): self.wTree.get_widget("bDelete").connect("clicked", self.on_bDelete_clicked) self.wTree.get_widget("bNext").connect("clicked", self.on_bNext_clicked) self.wTree.get_widget("bQuit").connect("clicked", self.on_bQuit_clicked) + self.ccdaemon.connect("crash", self.on_data_changed_cb, None) + # load data + self.load() + + def load(self): + self.appBar.push(0,"Loading dumps...") + self.loadDumpList() + self.appBar.pop(0) + + def loadDumpList(self): + #dumplist = getDumpList(dbmanager=self.ccdaemon) + pass + + def on_data_changed_cb(self, *args): + ret = gui_info_dialog("Another crash detected, do you want to refresh the data?",self.window) + if ret == gtk.RESPONSE_YES: + self.hydrate() + else: + pass + #print "got another crash, refresh gui?" + + def filter_dumps(self, model, miter, data): # this could be use for filtering the dumps return True @@ -58,45 +91,50 @@ class CCMainWindow(): self.window.show() def hydrate(self): - self.rows = self.ccdaemon.getDumps() - row_c = 0 - for row in self.rows: - self.dumpsListStore.append([row["Time"], row["Package"], row_c]) - row_c += 1 + self.dumpsListStore.clear() + dumplist = getDumpList(self.ccdaemon, refresh=True) + #self.rows = self.ccdaemon.getDumps() + #row_c = 0 + for entry in dumplist: + self.dumpsListStore.append([entry.getTime("%Y:%m:%d"),entry.getPackage(),entry]) + #row_c += 1 def on_tvDumps_cursor_changed(self,treeview): dumpsListStore, path = self.dlist.get_selection().get_selected_rows() if not path: return - # rewrite this OO - #DumpList class - row = self.rows[dumpsListStore.get_value(dumpsListStore.get_iter(path[0]), 2)] + # this should work until we keep the row object in the last position + dump = dumpsListStore.get_value(dumpsListStore.get_iter(path[0]), len(dumpsListStore)) lDate = self.wTree.get_widget("lDate") #move this to Dump class - t = datetime.fromtimestamp(int(row["Time"])) - date = t.strftime("%Y-%m-%d %H:%M:%S") - lDate.set_label(date) + lDate.set_label(dump.getTime("%Y.%m.%d %H:%M:%S")) lPackage = self.wTree.get_widget("lPackage") - lPackage.set_label(row["Package"]) - self.wTree.get_widget("lExecutable").set_label(row["Executable"]) - self.wTree.get_widget("lCRate").set_label(row["Count"]) + lPackage.set_label(dump.getPackage()) + self.wTree.get_widget("lExecutable").set_label(dump.getExecutable()) + self.wTree.get_widget("lCRate").set_label(dump.getCount()) #print self.rows[row] def on_bDelete_clicked(self, button): print "Delete" def on_bNext_clicked(self, button): - print "Next" + # FIXME don't duplicate the code, move to function + dumpsListStore, path = self.dlist.get_selection().get_selected_rows() + if not path: + return + dump = dumpsListStore.get_value(dumpsListStore.get_iter(path[0]), len(dumpsListStore)) + # show the report window with selected dump + report_dialog = ReporterDialog(dump) + report_dialog.run() def on_bQuit_clicked(self, button): - print "Quit" gtk.main_quit() if __name__ == "__main__": - cc = CCMainWindow() + cc = MainWindow() cc.hydrate() cc.show() gtk.main() |
