summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Gui/CCDump.py4
-rw-r--r--src/Gui/CCDumpList.py2
-rw-r--r--src/Gui/CCMainWindow.py126
-rw-r--r--src/Gui/CCReporterDialog.py223
-rw-r--r--src/Gui/PluginList.py7
-rw-r--r--src/Gui/ccgui.glade70
-rw-r--r--src/Gui/report.glade136
7 files changed, 382 insertions, 186 deletions
diff --git a/src/Gui/CCDump.py b/src/Gui/CCDump.py
index 2bb55dd0..3d6e8704 100644
--- a/src/Gui/CCDump.py
+++ b/src/Gui/CCDump.py
@@ -54,6 +54,7 @@ class Dump():
self.description = None
self.Message = None
self.Reported = None
+ self.analyzer = None
def getUUID(self):
return self.UUID[CD_CONTENT]
@@ -93,3 +94,6 @@ class Dump():
def getDescription(self):
return self.description[CD_CONTENT]
+
+ def getAnalyzerName(self):
+ return self.analyzer[CD_CONTENT]
diff --git a/src/Gui/CCDumpList.py b/src/Gui/CCDumpList.py
index 9d6bb2a2..f3df21ed 100644
--- a/src/Gui/CCDumpList.py
+++ b/src/Gui/CCDumpList.py
@@ -18,7 +18,7 @@ class DumpList(list):
for row in rows:
entry = Dump()
for column in row:
- log2(" DumpList.%s='%s'", column, row[column])
+ log2(" Dump.%s='%s'", column, row[column])
entry.__dict__[column] = row[column]
self.append(entry)
except Exception:
diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py
index 4a8329d8..74291fb2 100644
--- a/src/Gui/CCMainWindow.py
+++ b/src/Gui/CCMainWindow.py
@@ -2,7 +2,6 @@
import sys
import pwd
import getopt
-from glib import markup_escape_text
from abrt_utils import _, init_logging, log, log1, log2
import gobject
@@ -22,7 +21,7 @@ import CCDBusBackend
from CC_gui_functions import *
from CCDumpList import getDumpList
from CCDump import * # FILENAME_xxx, CD_xxx
-from CCReporterDialog import ReporterDialog
+from CCReporterDialog import ReporterDialog, ReporterSelector
from PluginsSettingsDialog import PluginsSettingsDialog
from SettingsDialog import SettingsDialog
from PluginList import getPluginInfoList
@@ -55,13 +54,6 @@ class MainWindow():
self.window.connect("destroy", self.destroy)
self.window.connect("focus-in-event", self.focus_in_cb)
- # pregress bar window to show while bt is being extracted
- self.pBarWindow = self.wTree.get_widget("pBarWindow")
- if self.pBarWindow:
- self.pBarWindow.connect("delete_event", self.sw_delete_event_cb)
- self.pBarWindow.set_transient_for(self.window)
- self.pBar = self.wTree.get_widget("pBar")
-
#init the dumps treeview
self.dlist = self.wTree.get_widget("tvDumps")
#rows of items with:
@@ -120,19 +112,19 @@ class MainWindow():
self.wTree.get_widget("miDelete").connect("activate", self.on_bDelete_clicked, self.dlist)
# 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)
self.ccdaemon.connect("abrt-error", self.error_cb)
- self.ccdaemon.connect("update", self.update_cb)
+ #self.ccdaemon.connect("update", self.update_cb)
# for now, just treat them the same (w/o this, we don't even see daemon warnings in logs!):
- self.ccdaemon.connect("warning", self.update_cb)
+ #self.ccdaemon.connect("warning", self.update_cb)
self.ccdaemon.connect("show", self.show_cb)
self.ccdaemon.connect("daemon-state-changed", self.on_daemon_state_changed_cb)
self.ccdaemon.connect("report-done", self.on_report_done_cb)
- # load data
- #self.load()
self.pluginlist = None
+ def on_report_done_cb(self, daemon, result):
+ self.hydrate()
+
def on_daemon_state_changed_cb(self, widget, state):
if state == "up":
self.hydrate() # refresh crash list
@@ -161,18 +153,12 @@ class MainWindow():
dialog = SettingsDialog(self.window, self.ccdaemon)
try:
dialog.hydrate()
- except Exception, e:
- gui_error_message(_("Can't show the settings dialog\n%s" % e))
+ except Exception, ex:
+ gui_error_message(_("Can't show the settings dialog\n%s" % ex))
return
dialog.show()
def error_cb(self, daemon, message=None):
- # try to hide the progressbar, we dont really care if it was visible ..
- try:
- gobject.source_remove(self.timer)
- self.pBarWindow.hide()
- except Exception:
- pass
gui_error_message(_("Unable to finish current task!\n%s" % message), parent_dialog=self.window)
def update_cb(self, daemon, message):
@@ -188,11 +174,6 @@ class MainWindow():
tvUpdates.set_buffer(buff)
tvUpdates.scroll_mark_onscreen(end)
- # call to update the progressbar
- def progress_update_cb(self, *args):
- self.pBar.pulse()
- return True
-
def hydrate(self):
n = None
self.dumpsListStore.clear()
@@ -272,7 +253,7 @@ class MainWindow():
def destroy(self, widget, data=None):
gtk.main_quit()
- def on_data_changed_cb(self, *args):
+ def on_data_changed_cb(self, *_args):
# FIXME mark the new entry somehow....
# remember the selected row
dumpsListStore, path = self.dlist.get_selection().get_selected_rows()
@@ -281,101 +262,18 @@ class MainWindow():
return
self.dlist.set_cursor(path[0])
- def on_report_done_cb(self, daemon, result):
- try:
- gobject.source_remove(self.timer)
- except:
- pass
- self.pBarWindow.hide()
- gui_report_dialog(result, self.window)
- self.hydrate()
-
- def on_analyze_complete_cb(self, daemon, report, pBarWindow):
- try:
- gobject.source_remove(self.timer)
- except:
- pass
- self.pBarWindow.hide()
-#FIXME - why we need this?? -> timeout warnings
-# try:
-# dumplist = getDumpList(self.ccdaemon)
-# except Exception, e:
-# print e
- if not report:
- gui_error_message(_("Unable to get report!\nDebuginfo is missing?"))
- return
- report_dialog = ReporterDialog(report, self.ccdaemon, log=self.updates, parent=self.window)
- # (response, report)
- response, result = report_dialog.run()
-
- if response == gtk.RESPONSE_APPLY:
- try:
- self.pBarWindow.show_all()
- self.timer = gobject.timeout_add(100, self.progress_update_cb)
- pluginlist = getPluginInfoList(self.ccdaemon)
- reporters_settings = pluginlist.getReporterPluginsSettings()
- log2("Report(result,reporters,settings):")
- log2(" result:%s", str(result))
- # Careful, this will print reporters_settings["Password"] too
- log2(" settings:%s", str(reporters_settings))
- self.ccdaemon.Report(result, ["reporter1", "reporter2"], reporters_settings)
- log2("Report() returned")
- #self.hydrate()
- except Exception, ex:
- gui_error_message(_("Reporting failed!\n%s" % ex))
- # -50 == REFRESH
- elif response == -50:
- self.refresh_report(report)
-
- def refresh_report(self, report):
- self.updates = ""
- self.pBarWindow.show_all()
- self.timer = gobject.timeout_add(100, self.progress_update_cb)
-
- # show the report window with selected report
- try:
- self.ccdaemon.getReport(report[CD_UUID][CD_CONTENT], force=1)
- except Exception, ex:
- # FIXME #3 dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply
- # do this async and wait for yum to end with debuginfoinstal
- if self.timer:
- gobject.source_remove(self.timer)
- self.pBarWindow.hide()
- gui_error_message(_("Error getting the report: %s" % ex))
- return
-
def on_bReport_clicked(self, button):
dumpsListStore, path = self.dlist.get_selection().get_selected_rows()
self.on_dumpRowActivated(self.dlist, None, path, None)
- def on_dumpRowActivated(self, treeview, iter, path, user_data=None):
- self.updates = ""
- # FIXME don't duplicate the code, move to function
+ def on_dumpRowActivated(self, treeview, it, path, user_data=None):
dumpsListStore, path = treeview.get_selection().get_selected_rows()
if not path:
return
- #self.pBar.show()
- self.pBarWindow.show_all()
- self.timer = gobject.timeout_add(100, self.progress_update_cb)
-
dump = dumpsListStore.get_value(dumpsListStore.get_iter(path[0]), dumpsListStore.get_n_columns()-1)
- # show the report window with selected dump
- try:
- self.ccdaemon.getReport(dump.getUUID())
- except Exception, ex:
- # FIXME #3 dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply
- # do this async and wait for yum to end with debuginfoinstal
- if self.timer:
- gobject.source_remove(self.timer)
- self.pBarWindow.hide()
- gui_error_message(_("Error getting the report: %s" % ex))
- return
- def sw_delete_event_cb(self, widget, event, data=None):
- if self.timer:
- gobject.source_remove(self.timer)
- widget.hide()
- return True
+ rs = ReporterSelector(dump, self.ccdaemon, parent=self.window)
+ rs.show()
def delete_event_cb(self, widget, event, data=None):
gtk.main_quit()
diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py
index 989f7cbe..7cbe2197 100644
--- a/src/Gui/CCReporterDialog.py
+++ b/src/Gui/CCReporterDialog.py
@@ -2,8 +2,8 @@
import pygtk
pygtk.require("2.0")
import gtk
+import gobject
import gtk.glade
-import pango
import sys
from CC_gui_functions import *
import CellRenderers
@@ -326,3 +326,224 @@ class ReporterDialog():
result = self.window.run()
self.window.destroy()
return (result, self.report)
+
+class ReporterSelector():
+ def __init__(self, crashdump, daemon, log=None, parent=None):
+ self.connected_signals = []
+ self.updates = ""
+ self.daemon = daemon
+ self.dump = crashdump
+ self.selected_reporters = []
+ #FIXME: cache settings! Create some class to represent it like PluginList
+ self.settings = daemon.getSettings()
+ pluginlist = getPluginInfoList(daemon)
+ self.reporters = []
+ AnalyzerActionsAndReporters = self.settings["AnalyzerActionsAndReporters"]
+ for reporter_name in AnalyzerActionsAndReporters[crashdump.getAnalyzerName()].split(','):
+ reporter = pluginlist.getReporterByName(reporter_name)
+ if reporter:
+ self.reporters.append(reporter)
+
+ builderfile = "%s/report.glade" % sys.path[0]
+ self.builder = gtk.Builder()
+ self.builder.add_from_file(builderfile)
+ self.window = self.builder.get_object("w_reporters")
+ if parent:
+ self.window.set_transient_for(parent)
+ self.window.set_modal(True)
+ self.connect_signal(self.window, "delete-event", self.on_window_delete)
+ self.connect_signal(self.window, "destroy-event", self.on_window_delete)
+
+ self.pBarWindow = self.builder.get_object("pBarWindow")
+
+ b_cancel = self.builder.get_object("b_close")
+ self.connect_signal(b_cancel, "clicked", self.on_close_clicked)
+ reporters_vbox = self.builder.get_object("vb_reporters")
+ for reporter in self.reporters:
+ button = gtk.Button(str(reporter))
+ self.connect_signal(button, "clicked", self.on_reporter_clicked, data=reporter)
+ reporters_vbox.pack_start(button)
+
+ # progress bar window to show while bt is being extracted
+ self.pBarWindow = self.builder.get_object("pBarWindow")
+ if self.pBarWindow:
+ self.connect_signal(self.pBarWindow, "delete_event", self.sw_delete_event_cb)
+ if parent:
+ self.pBarWindow.set_transient_for(parent)
+ else:
+ self.pBarWindow.set_transient_for(self.window)
+ self.pBar = self.builder.get_object("pBar")
+
+ # connect handlers for daemon signals
+ #self.ccdaemon.connect("abrt-error", self.error_cb)
+ self.connect_signal(daemon, "update", self.update_cb)
+ # for now, just treat them the same (w/o this, we don't even see daemon warnings in logs!):
+ #self.ccdaemon.connect("warning", self.update_cb)
+ #self.ccdaemon.connect("show", self.show_cb)
+ #self.ccdaemon.connect("daemon-state-changed", self.on_daemon_state_changed_cb)
+ self.connect_signal(daemon, "report-done", self.on_report_done_cb)
+ self.connect_signal(daemon, "analyze-complete", self.on_analyze_complete_cb, self.pBarWindow)
+
+ def connect_signal(self, obj, signal, callback, data=None):
+ if data:
+ signal_id = obj.connect(signal, callback, data)
+ else:
+ signal_id = obj.connect(signal, callback)
+ self.connected_signals.append((obj, signal_id))
+
+ def disconnect_signals(self):
+ # we need to disconnect all signals in order to break all references
+ # to this object, otherwise python won't destroy this object and the
+ # signals emmited by daemon will get caught by multiple instances of
+ # this class
+ for obj, signal_id in self.connected_signals:
+ obj.disconnect(signal_id)
+
+ def update_cb(self, daemon, message):
+ self.updates += message
+ if self.updates[-1] != '\n':
+ self.updates += '\n'
+ message = message.replace('\n',' ')
+ self.builder.get_object("lStatus").set_text(message)
+ buff = gtk.TextBuffer()
+ buff.set_text(self.updates)
+ end = buff.get_insert()
+ tvUpdates = self.builder.get_object("tvUpdates")
+ tvUpdates.set_buffer(buff)
+ tvUpdates.scroll_mark_onscreen(end)
+
+ def sw_delete_event_cb(self, widget, event, data=None):
+ if self.timer:
+ gobject.source_remove(self.timer)
+ widget.hide()
+ return True
+
+ def show(self):
+ if not self.reporters:
+ gui_error_message(_("No reporter plugin available for this type of crash\n"
+ "Please check abrt.conf."))
+ elif len(self.reporters) > 1:
+ self.builder.get_object("vb_reporters").show_all()
+ self.window.show()
+ else:
+ # we have only one reporter in the list
+ self.selected_reporters = [str(self.reporters[0])]
+ self.show_report()
+
+ def on_reporter_clicked(self, widget, reporter):
+ self.selected_reporters = [str(reporter)]
+ self.show_report()
+
+ def on_close_clicked(self, widget):
+ self.disconnect_signals()
+ self.window.destroy()
+
+ def on_window_delete(self, window, event):
+ self.disconnect_signals()
+ return False
+
+ def on_report_done_cb(self, daemon, result):
+ try:
+ gobject.source_remove(self.timer)
+ except:
+ pass
+ self.pBarWindow.hide()
+ gui_report_dialog(result, self.window)
+
+ if not self.window.get_property("visible"):
+ self.disconnect_signals()
+
+ def on_analyze_complete_cb(self, daemon, report, pBarWindow):
+ try:
+ gobject.source_remove(self.timer)
+ except:
+ pass
+ self.pBarWindow.hide()
+#FIXME - why we need this?? -> timeout warnings
+# try:
+# dumplist = getDumpList(self.daemon)
+# except Exception, e:
+# print e
+ if not report:
+ gui_error_message(_("Unable to get report!\nDebuginfo is missing?"))
+ return
+
+ # if we have only one reporter enabled, the window with
+ # the selection is not shown, so we can't use it as a parent
+ # and we use the mainwindow instead
+ if self.window.get_property("visible"):
+ parent_window = self.window
+ else:
+ parent_window = self.window.get_transient_for()
+
+ report_dialog = ReporterDialog(report, self.daemon, log=self.updates, parent=parent_window)
+ # (response, report)
+ response, result = report_dialog.run()
+
+ if response == gtk.RESPONSE_APPLY:
+ try:
+ self.pBarWindow.show_all()
+ self.timer = gobject.timeout_add(100, self.progress_update_cb)
+ pluginlist = getPluginInfoList(self.daemon)
+ reporters_settings = pluginlist.getReporterPluginsSettings()
+ log2("Report(result,reporters,settings):")
+ log2(" result:%s", str(result))
+ # Careful, this will print reporters_settings["Password"] too
+ log2(" settings:%s", str(reporters_settings))
+ self.daemon.Report(result, self.selected_reporters, reporters_settings)
+ log2("Report() returned")
+ #self.hydrate()
+ except Exception, ex:
+ gui_error_message(_("Reporting failed!\n%s" % ex))
+ # -50 == REFRESH
+ elif response == -50:
+ self.refresh_report(report)
+
+ elif not self.window.get_property("visible"):
+ self.disconnect_signals()
+
+ # call to update the progressbar
+ def progress_update_cb(self, *args):
+ self.pBar.pulse()
+ return True
+
+ def refresh_report(self, report):
+ self.updates = ""
+ self.pBarWindow.show_all()
+ self.timer = gobject.timeout_add(100, self.progress_update_cb)
+
+ # show the report window with selected report
+ try:
+ self.daemon.getReport(report[CD_UUID][CD_CONTENT], force=1)
+ except Exception, ex:
+ # FIXME #3 dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply
+ # do this async and wait for yum to end with debuginfoinstal
+ if self.timer:
+ gobject.source_remove(self.timer)
+ self.pBarWindow.hide()
+ gui_error_message(_("Error getting the report: %s" % ex))
+ return
+
+ def show_report(self):
+ self.updates = ""
+ # FIXME don't duplicate the code, move to function
+ #self.pBar.show()
+ self.pBarWindow.show_all()
+ self.timer = gobject.timeout_add(100, self.progress_update_cb)
+
+ # show the report window with selected dump
+ # when getReport is done it emits "analyze-complete" and on_analyze_complete_cb is called
+ # FIXME: does it make sense to change it to use callback rather then signal emitting?
+ try:
+ self.daemon.getReport(self.dump.getUUID())
+ except Exception, ex:
+ # FIXME #3 dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply
+ # do this async and wait for yum to end with debuginfoinstal
+ if self.timer:
+ gobject.source_remove(self.timer)
+ self.pBarWindow.hide()
+ gui_error_message(_("Error getting the report: %s" % ex))
+ return
+
+ def __del__(self):
+ log1("ReporterSelector: instance is about to be garbage-collected")
diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py
index 6105b04e..288dfccf 100644
--- a/src/Gui/PluginList.py
+++ b/src/Gui/PluginList.py
@@ -24,6 +24,13 @@ class PluginInfoList(list):
else:
log("PluginInfoList: db == None")
+ def getReporterByName(self, name):
+ try:
+ return [x for x in self if x["Name"] == name][0]
+ except:
+ # if such reporter doesnt't exist return None
+ return None
+
def getEnabledPlugins(self):
return [x for x in self if x["Enabled"] == 'yes']
diff --git a/src/Gui/ccgui.glade b/src/Gui/ccgui.glade
index 2291ee6f..5b102f46 100644
--- a/src/Gui/ccgui.glade
+++ b/src/Gui/ccgui.glade
@@ -2,76 +2,6 @@
<glade-interface>
<!-- interface-requires gtk+ 2.14 -->
<!-- interface-naming-policy toplevel-contextual -->
- <widget class="GtkWindow" id="pBarWindow">
- <property name="width_request">270</property>
- <property name="border_width">12</property>
- <property name="title" translatable="yes">Please wait..</property>
- <property name="modal">True</property>
- <property name="window_position">center-on-parent</property>
- <property name="default_width">470</property>
- <property name="icon_name">abrt</property>
- <property name="transient_for">main_window3</property>
- <child>
- <widget class="GtkVBox" id="vbox1">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">12</property>
- <child>
- <widget class="GtkLabel" id="lStatus">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <widget class="GtkProgressBar" id="pBar">
- <property name="visible">True</property>
- <property name="text_xalign">0</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkExpander" id="expander1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">etched-in</property>
- <child>
- <widget class="GtkTextView" id="tvUpdates">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="lUpdates">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Details</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
<widget class="GtkAboutDialog" id="about">
<property name="border_width">5</property>
<property name="title" translatable="yes">About ABRT</property>
diff --git a/src/Gui/report.glade b/src/Gui/report.glade
index 7b3aac4a..0213026b 100644
--- a/src/Gui/report.glade
+++ b/src/Gui/report.glade
@@ -5,6 +5,8 @@
<object class="GtkDialog" id="reporter_dialog">
<property name="border_width">5</property>
<property name="title" translatable="yes">Automatic Bug Reporting Tool</property>
+ <property name="modal">True</property>
+ <property name="icon_name">abrt</property>
<property name="type_hint">normal</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
@@ -649,4 +651,138 @@
<action-widget response="-10">bSend</action-widget>
</action-widgets>
</object>
+ <object class="GtkWindow" id="w_reporters">
+ <property name="title" translatable="yes">Reporter Selector</property>
+ <property name="icon_name">abrt</property>
+ <child>
+ <object class="GtkVBox" id="vb_main">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xpad">5</property>
+ <property name="ypad">10</property>
+ <property name="label" translatable="yes">&lt;b&gt;Where do you want to report this incident?&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vb_reporters">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="padding">9</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="b_close">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkWindow" id="pBarWindow">
+ <property name="width_request">270</property>
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Please wait..</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="default_width">470</property>
+ <property name="icon_name">abrt</property>
+ <property name="transient_for">w_reporters</property>
+ <child>
+ <object class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="lStatus">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="pBar">
+ <property name="visible">True</property>
+ <property name="text_xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">etched-in</property>
+ <child>
+ <object class="GtkTextView" id="tvUpdates">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="lUpdates">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Details</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
</interface>