diff options
| author | Karel Klic <kklic@redhat.com> | 2011-03-01 12:08:36 +0100 |
|---|---|---|
| committer | Karel Klic <kklic@redhat.com> | 2011-03-01 12:08:36 +0100 |
| commit | 85f639b7fe277ba327e5013e5b101b4a67f14e1d (patch) | |
| tree | 7caa3999e8c987e3ddbc26f4bfbbdc73defca73f /src/gui | |
| parent | fb52104af74bbf6eeda394880666df40b4354aba (diff) | |
| parent | 77468fcdd7cc05db52320c373a24a5490ff32f52 (diff) | |
merge changes from master
Diffstat (limited to 'src/gui')
| -rw-r--r-- | src/gui/CCDBusBackend.py | 15 | ||||
| -rw-r--r-- | src/gui/CCDump.py | 11 | ||||
| -rw-r--r-- | src/gui/CCMainWindow.py | 16 | ||||
| -rw-r--r-- | src/gui/CCReporterDialog.py | 578 | ||||
| -rw-r--r-- | src/gui/CReporterAssistant.py | 68 | ||||
| -rw-r--r-- | src/gui/CellRenderers.py | 66 | ||||
| -rw-r--r-- | src/gui/Makefile.am | 4 | ||||
| -rw-r--r-- | src/gui/SettingsDialog.py | 53 | ||||
| -rw-r--r-- | src/gui/ccgui.glade | 42 | ||||
| -rw-r--r-- | src/gui/progress_window.glade | 19 | ||||
| -rw-r--r-- | src/gui/settings.glade | 295 |
11 files changed, 139 insertions, 1028 deletions
diff --git a/src/gui/CCDBusBackend.py b/src/gui/CCDBusBackend.py index 3fa95eb9..d2b867c7 100644 --- a/src/gui/CCDBusBackend.py +++ b/src/gui/CCDBusBackend.py @@ -21,6 +21,7 @@ class DBusManager(gobject.GObject): # and later with policyKit bus = None def __init__(self): + session = None # binds the dbus to glib mainloop DBusGMainLoop(set_as_default=True) @@ -60,7 +61,7 @@ class DBusManager(gobject.GObject): # signal emited to update gui with current status gobject.signal_new("update", self, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)) # signal emited to show gui if user try to run it again - gobject.signal_new("show", self, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) + gobject.signal_new("show_gui", self, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) gobject.signal_new("daemon-state-changed", self, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)) gobject.signal_new("report-done", self, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)) @@ -211,11 +212,13 @@ class DBusManager(gobject.GObject): def getSettings(self): return self.daemon().GetSettings() - def setSettings(self, settings): - # FIXME: STUB!!!! - log1("setSettings stub") - retval = self.daemon().SetSettings(self.daemon().GetSettings()) - print ">>>", retval + ### looks unused to me. + ### Ok to grep for setSettings and delete after 2011-04-01. + ### def setSettings(self, settings): + ### # FIXME: STUB!!!! + ### log1("setSettings stub") + ### retval = self.daemon().SetSettings(self.daemon().GetSettings()) + ### print ">>>", retval def __del__(self): log1("CCDBusBackend is about to be deleted") diff --git a/src/gui/CCDump.py b/src/gui/CCDump.py index df5c18aa..10d7c2a3 100644 --- a/src/gui/CCDump.py +++ b/src/gui/CCDump.py @@ -3,7 +3,7 @@ from datetime import datetime from abrt_utils import _, init_logging, log, log1, log2 -# Keep in sync with [abrt_]crash_dump.h! +# Keep in sync with [abrt_]crash_data.h! CD_TYPE = 0 CD_EDITABLE = 1 CD_CONTENT = 2 @@ -25,10 +25,9 @@ FILENAME_CRASH_FUNCTION = "crash_function" FILENAME_ARCHITECTURE = "architecture" FILENAME_KERNEL = "kernel" FILENAME_TIME = "time" -FILENAME_RELEASE = "release" +FILENAME_OS_RELEASE = "os_release" FILENAME_PACKAGE = "package" FILENAME_COMPONENT = "component" -FILENAME_DESCRIPTION = "description" FILENAME_COMMENT = "comment" FILENAME_REPRODUCE = "reproduce" FILENAME_RATING = "rating" @@ -129,7 +128,11 @@ class Dump(): return self.analyzer def get_release(self): - return self.release + # Old dump dir format compat. Delete in abrt-2.1: + try: + return self.os_release + except AttributeError: + return self.release # old name def get_reason(self): return self.reason diff --git a/src/gui/CCMainWindow.py b/src/gui/CCMainWindow.py index 651c8e54..c6642f78 100644 --- a/src/gui/CCMainWindow.py +++ b/src/gui/CCMainWindow.py @@ -21,7 +21,6 @@ import CCDBusBackend from CC_gui_functions import * from CCDumpList import getDumpList from CCDump import * # FILENAME_xxx, CD_xxx -from CCReporterDialog import ReporterDialog, ReporterSelector from CReporterAssistant import ReporterAssistant from PluginsSettingsDialog import PluginsSettingsDialog from SettingsDialog import SettingsDialog @@ -39,6 +38,7 @@ class MainWindow(): self.gladefile = "%s/ccgui.glade" % sys.path[0] self.wTree = gtk.glade.XML(self.gladefile) + #Get the Main Window, and connect the "destroy" event self.window = self.wTree.get_widget("main_window") if self.window: @@ -89,9 +89,10 @@ class MainWindow(): self.wTree.get_widget("bReport").connect("clicked", self.on_bReport_clicked) self.wTree.get_widget("b_close").connect("clicked", self.on_bQuit_clicked) self.wTree.get_widget("b_copy").connect("clicked", self.on_b_copy_clicked) - self.wTree.get_widget("b_help").connect("clicked", self.on_miAbout_clicked) + self.wTree.get_widget("b_help").connect("clicked", self.on_miOnlineHelp_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("miOnlineHelp").connect("activate", self.on_miOnlineHelp_clicked) self.wTree.get_widget("miPlugins").connect("activate", self.on_miPreferences_clicked) self.wTree.get_widget("miPreferences").connect("activate", self.on_miSettings_clicked) self.wTree.get_widget("miReport").connect("activate", self.on_bReport_clicked) @@ -102,7 +103,7 @@ class MainWindow(): #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("show", self.show_cb) + self.ccdaemon.connect("show_gui", 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) @@ -130,6 +131,10 @@ class MainWindow(): result = dialog.run() dialog.hide() + def on_miOnlineHelp_clicked(self, widget): + # opens default browser and shows ABRT chapter from deployment guide + gtk.show_uri(None, "http://docs.fedoraproject.org/en-US/Fedora/14/html/Deployment_Guide/ch-abrt.html", gtk.gdk.CURRENT_TIME) + def on_miPreferences_clicked(self, widget): dialog = PluginsSettingsDialog(self.window,self.ccdaemon) dialog.hydrate() @@ -243,6 +248,7 @@ class MainWindow(): # process the labels in sw_details # hide the fields that are not filled by daemon - e.g. comments # and how to reproduce + for field in dump.not_required_fields: self.wTree.get_widget("l_%s" % field.lower()).hide() self.wTree.get_widget("l_%s_heading" % field.lower()).hide() @@ -342,7 +348,7 @@ class MainWindow(): ("Command:", dump.cmdline), ("Reason:", dump.reason), ("Comment:", dump.comment), - ("Bug Reports:", dump.Message), + ("Bug Reports:", dump.message), ] dumpinfo_text = "" for line in dumpinfo: @@ -394,7 +400,7 @@ class MainWindow(): sys.exit() def show(self): - self.window.show() + self.window.show_all() def show_cb(self, daemon): if self.window: diff --git a/src/gui/CCReporterDialog.py b/src/gui/CCReporterDialog.py deleted file mode 100644 index b34baf87..00000000 --- a/src/gui/CCReporterDialog.py +++ /dev/null @@ -1,578 +0,0 @@ -# -*- coding: utf-8 -*- -import pygtk -pygtk.require("2.0") -import gtk -import gobject -import sys -from CC_gui_functions import * -import CellRenderers -from ABRTPlugin import PluginInfo -from PluginSettingsUI import PluginSettingsUI -from PluginList import getPluginInfoList -from CCDump import * # FILENAME_xxx, CD_xxx -from abrt_utils import _, log, log1, log2, get_verbose_level, g_verbose - -# FIXME - create method or smth that returns type|editable|content - -# response -REFRESH = -50 -SHOW_LOG = -60 - -# default texts -COMMENT_HINT_TEXT = _("Brief description of how to reproduce this or what you did...") -HOW_TO_HINT_TEXT = "1.\n2.\n3.\n" - -class ReporterDialog(): - """Reporter window""" - def __init__(self, report, daemon, log=None, parent=None): - self.editable = [] - self.row_dict = {} - self.report = report - #Set the Glade file - # FIXME add to path - builderfile = "%s/report.glade" % sys.path[0] - self.builder = gtk.Builder() - self.builder.add_from_file(builderfile) - #Get the Main Window, and connect the "destroy" event - self.window = self.builder.get_object("reporter_dialog") - self.window.set_default_size(-1, 800) - self.window.connect("response", self.on_response, daemon) - if parent: - self.window.set_position(gtk.WIN_POS_CENTER_ON_PARENT) - self.window.set_transient_for(parent) - self.window.set_modal(True) - else: - self.window.set_position(gtk.WIN_POS_CENTER) - - # comment textview - self.tvComment = self.builder.get_object("tvComment") - self.tvComment.connect("focus-in-event", self.on_comment_focus_cb) - self.show_hint_comment = 1 - - # "how to reproduce" textview - self.tevHowToReproduce = self.builder.get_object("tevHowToReproduce") - - self.builder.get_object("fErrors").hide() - bLog = self.builder.get_object("bLog") - #if g_verbose > 0: - doesn't work! why?! - if get_verbose_level() > 0: - bLog.connect("clicked", self.show_log_cb, log) - else: - bLog.unset_flags(gtk.VISIBLE) - tb_send_bt = self.builder.get_object("cbSendBacktrace") - tb_send_bt.connect("toggled", self.on_send_backtrace_toggled) - try: - tb_send_bt.get_child().modify_fg(gtk.STATE_NORMAL,gtk.gdk.color_parse("red")) - except Exception, ex: - # we don't want gui to die if it fails to set the button color - log(ex) - self.allow_send() - self.hydrate() - - def check_backtrace(self): - print "checking backtrace" - - def warn_user(self, warnings): - # FIXME: show in lError - fErrors = self.builder.get_object("fErrors") - lErrors = self.builder.get_object("lErrors") - warning_lbl = None - for warning in warnings: - if warning_lbl: - warning_lbl += "\n* %s" % warning - else: - warning_lbl = "* %s" % warning - lErrors.set_label(warning_lbl) - fErrors.show_all() - - def hide_warning(self): - fErrors = self.builder.get_object("fErrors") - lErrors = self.builder.get_object("lErrors") - fErrors.hide() - - def allow_send(self): - self.hide_warning() - bSend = self.builder.get_object("bSend") - SendBacktrace = self.builder.get_object("cbSendBacktrace").get_active() - send = True - error_msgs = [] - try: - rating = int(self.report[FILENAME_RATING][CD_CONTENT]) - except: - rating = None - # active buttons acording to required fields - # if an backtrace has rating use it - if not SendBacktrace: - send = False - error_msgs.append(_("You must check the backtrace for sensitive data.")) - # we have both SendBacktrace and rating - if rating != None: - try: - package = self.report[FILENAME_PACKAGE][CD_CONTENT] - # if we don't have package for some reason - except: - package = None - # not usable report - if int(self.report[FILENAME_RATING][CD_CONTENT]) < 3: - if package: - error_msgs.append(_("Reporting disabled because the backtrace is unusable.\nPlease try to install debuginfo manually using the command: <b>debuginfo-install %s</b> \nthen use the Refresh button to regenerate the backtrace." % package[0:package.rfind('-',0,package.rfind('-'))])) - else: - error_msgs.append(_("The backtrace is unusable, you cannot report this!")) - send = False - # probably usable 3 - elif int(self.report[FILENAME_RATING][CD_CONTENT]) < 4: - error_msgs.append(_("The backtrace is incomplete, please make sure you provide the steps to reproduce.")) - - if error_msgs: - self.warn_user(error_msgs) - bSend.set_sensitive(send) - if not send: - bSend.set_tooltip_text(_("Reporting disabled, please fix the problems shown above.")) - else: - bSend.set_tooltip_text(_("Sends the report using the selected plugin.")) - - def on_send_backtrace_toggled(self, toggle_button): - self.allow_send() - - def show_log_cb(self, widget, log): - show_log(log, parent=self.window) - - # this callback is called when user press Cancel or Report button in Report dialog - def on_response(self, dialog, response_id, daemon): - # the button has been pressed (probably) - if response_id == gtk.RESPONSE_APPLY: - if not (self.check_report()): - dialog.stop_emission("response") - self.builder.get_object("bSend").stop_emission("clicked") - if response_id == SHOW_LOG: - # prevent the report dialog from quitting the run() and closing itself - dialog.stop_emission("response") - - def on_send_toggled(self, cell, path, model): - model[path][3] = not model[path][3] - - def on_comment_focus_cb(self, widget, event): - if self.show_hint_comment: - # clear "hint" text by supplying a fresh, empty TextBuffer - widget.set_buffer(gtk.TextBuffer()) - self.show_hint_comment = 0 - - def set_label(self, label_widget, text): - if len(text) > label_widget.get_max_width_chars(): - label_widget.set_tooltip_text(text) - label_widget.set_text(text) - - def hydrate(self): - self.editable = [] - self.old_comment = COMMENT_HINT_TEXT - self.old_how_to_reproduce = HOW_TO_HINT_TEXT - for item in self.report: - try: - log2("report[%s]:%s/%s/%s", item, self.report[item][0], self.report[item][1], self.report[item][2][0:20]) - except: - pass - - if item == FILENAME_BACKTRACE: - buff = gtk.TextBuffer() - tvBacktrace = self.builder.get_object("tvBacktrace") - buff.set_text(self.report[item][CD_CONTENT]) - tvBacktrace.set_buffer(buff) - continue - - if item == FILENAME_COMMENT: - try: - if self.report[item][CD_CONTENT]: - self.old_comment = self.report[item][CD_CONTENT] - except Exception, e: - pass - continue - - if item == FILENAME_REPRODUCE: - try: - if self.report[item][CD_CONTENT]: - self.old_how_to_reproduce = self.report[item][CD_CONTENT] - except Exception, e: - pass - continue - - if self.report[item][CD_TYPE] == CD_SYS: - continue - - # item name 0| value 1| editable? 2| toggled? 3| visible?(attachment)4 - # FIXME: handle editable fields - if self.report[item][CD_TYPE] == CD_BIN: - self.builder.get_object("fAttachment").show() - vbAttachments = self.builder.get_object("vbAttachments") - toggle = gtk.CheckButton(self.report[item][CD_CONTENT]) - vbAttachments.pack_start(toggle) - # bind item to checkbox - toggle.item = item - #FIXME: temporary workaround, in 1.0.4 reporters don't care - # about this, they just send what they want to - # TicketUploader even sends coredump!! - #toggle.show() - continue - - # It must be CD_TXT field - item_label = self.builder.get_object("l%s" % item) - if item_label: - self.set_label(item_label, self.report[item][CD_CONTENT]) - else: - # no widget to show this item - # probably some new item need to adjust the GUI! - # FIXME: add some window+button to show all the info - # in raw form (smth like the old report dialog) - pass - #end for - - buff = gtk.TextBuffer() - self.show_hint_comment = (self.old_comment == COMMENT_HINT_TEXT) - if self.show_hint_comment: - buff.set_text(COMMENT_HINT_TEXT) - else: - buff.set_text(self.old_comment) - self.tvComment.set_buffer(buff) - - buff = gtk.TextBuffer() - if self.old_how_to_reproduce == "": - buff.set_text(HOW_TO_HINT_TEXT) - else: - buff.set_text(self.old_how_to_reproduce) - self.tevHowToReproduce.set_buffer(buff) - - def dehydrate(self): - ## # handle attachments - ## vbAttachments = self.builder.get_object("vbAttachments") - ## for attachment in vbAttachments.get_children(): - ## #print "%s file %s" % (["not sending","sending"][attachment.get_active()], attachment.get_label()) - ## del self.report[attachment.item] - - # handle comment - buff = self.tvComment.get_buffer() - text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) - if self.old_comment != text: - self.report[FILENAME_COMMENT] = [CD_TXT, 'y', text] - # handle how to reproduce - buff = self.tevHowToReproduce.get_buffer() - text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) - if self.old_how_to_reproduce != text: - self.report[FILENAME_REPRODUCE] = [CD_TXT, 'y', text] - # handle backtrace - tev_backtrace = self.builder.get_object("tvBacktrace") - buff = tev_backtrace.get_buffer() - text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) - self.report[FILENAME_BACKTRACE] = [CD_TXT, 'y', text] - - def check_report(self): - # FIXME: check the report for passwords and some other potentially - # sensitive info - self.dehydrate() - return True - - def run(self): - 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"] - try: - reporters = None - try: - reporters = AnalyzerActionsAndReporters[self.dump.getAnalyzerName()+":"+self.dump.getPackageName()] - except KeyError: - pass - if not reporters: - reporters = AnalyzerActionsAndReporters[crashdump.getAnalyzerName()] - for reporter_name in reporters.split(','): - reporter = pluginlist.getReporterByName(reporter_name) - if reporter: - self.reporters.append(reporter) - except KeyError: - # Analyzer has no associated reporters. - pass - - 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") - b_cancel = self.builder.get_object("b_close") - - if parent: - self.window.set_position(gtk.WIN_POS_CENTER_ON_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.connect_signal(b_cancel, "clicked", self.on_close_clicked) - else: - # if we don't have parent we want to quit the mainloop on close - self.window.set_position(gtk.WIN_POS_CENTER) - self.connect_signal(self.window, "delete-event", gtk.main_quit) - self.connect_signal(self.window, "destroy-event", gtk.main_quit) - self.connect_signal(b_cancel, "clicked", gtk.main_quit) - - - self.pBarWindow = self.builder.get_object("pBarWindow") - self.pBarWindow.set_transient_for(self.window) - - 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 cleanup_and_exit(self): - if not self.window.get_property("visible"): - self.disconnect_signals() - # if the reporter selector doesn't have a parent - if not self.window.get_transient_for(): - gtk.main_quit() - - 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_config_plugin_clicked(self, button, plugin, image): - ui = PluginSettingsUI(plugin, parent=self.window) - ui.hydrate() - response = ui.run() - if response == gtk.RESPONSE_APPLY: - ui.dehydrate() - if plugin.Settings.check(): - try: - plugin.save_settings_on_client_side() - except Exception, e: - gui_error_message(_("Cannot save plugin settings:\n %s" % e)) - box = image.get_parent() - im = gtk.Image() - im.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_MENU) - box.remove(image) - box.pack_start(im, expand = False, fill = False) - im.show() - image.destroy() - button.set_sensitive(False) - elif response == gtk.RESPONSE_CANCEL: - log1("cancel") - ui.destroy() - - def check_settings(self, reporters): - wrong_conf_plugs = [] - for reporter in reporters: - if reporter.Settings.check() == False: - wrong_conf_plugs.append(reporter) - - if wrong_conf_plugs: - gladefile = "%s%ssettings_wizard.glade" % (sys.path[0],"/") - builder = gtk.Builder() - builder.add_from_file(gladefile) - dialog = builder.get_object("WrongSettings") - vbWrongSettings = builder.get_object("vbWrongSettings") - for plugin in wrong_conf_plugs: - hbox = gtk.HBox() - hbox.set_spacing(6) - image = gtk.Image() - image.set_from_stock(gtk.STOCK_CANCEL, gtk.ICON_SIZE_MENU) - button = gtk.Button(_("Configure %s options" % plugin.getName())) - button.connect("clicked", self.on_config_plugin_clicked, plugin, image) - hbox.pack_start(button) - hbox.pack_start(image, expand = False, fill = False) - vbWrongSettings.pack_start(hbox) - vbWrongSettings.show_all() - dialog.set_transient_for(self.window) - dialog.set_modal(True) - response = dialog.run() - dialog.destroy() - if response != gtk.RESPONSE_YES: - # user cancelled reporting - return False - return True - - def on_reporter_clicked(self, widget, reporter): - self.selected_reporters = [reporter] - if self.check_settings(self.selected_reporters): - 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) - - self.cleanup_and_exit() - - 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!\nIs debuginfo 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) - else: - self.cleanup_and_exit() - - # 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.start_job(report[CD_DUMPDIR][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 acquiring 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.start_job(self.dump.getDumpDir()) - 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 acquiring the report: %s" % ex)) - return - - def __del__(self): - log1("ReporterSelector: instance is about to be garbage-collected") diff --git a/src/gui/CReporterAssistant.py b/src/gui/CReporterAssistant.py index d998b870..300ddc3f 100644 --- a/src/gui/CReporterAssistant.py +++ b/src/gui/CReporterAssistant.py @@ -23,12 +23,48 @@ MISSING_BACKTRACE_TEXT = _("Crash info doesn't contain a backtrace") DEFAULT_WIDTH = 800 DEFAULT_HEIGHT = 500 + +class Log(gtk.ScrolledWindow): + def __init__(self, log=""): + gtk.ScrolledWindow.__init__(self) + self.tv = gtk.TextView() + self.tv.set_editable(False) + self.add(self.tv) + # FIXME: log shouldn't be None + self.buff = gtk.TextBuffer() + self.buff.set_text(log) + self.tv.set_buffer(self.buff) + self.scroll = False + + def append_line(self, text): + end_iter = self.buff.get_end_iter() + self.buff.insert(end_iter, "%s\n" % text) + self.scroll_to_end() + + + def append_warning(self, text): + """ stub """ + pass + + def append_error(self, text): + """ do we need this? shouldn't error be an exception? """ + pass + + def set_scroll(self, scroll): + """ enables/disables scrolling to end, when new text is added """ + self.scroll = scroll + + def scroll_to_end(self): + if self.scroll: + mark = self.buff.get_insert() + self.tv.scroll_mark_onscreen(mark) + class ReporterAssistant(): def __init__(self, report, daemon, log=None, parent=None): self.connected_signals = [] self.plugins_cb = [] self.daemon = daemon - self.updates = "" + self.updates = [] self.pdict = {} self.report = report self.parent = parent @@ -37,6 +73,8 @@ class ReporterAssistant(): self.report_has_bt = False self.selected_report_events = [] self.ev_warning = None + self.log = Log() + self.log.set_scroll(True) """ create the assistant """ self.assistant = gtk.Assistant() self.assistant.set_icon_name("abrt") @@ -61,6 +99,8 @@ class ReporterAssistant(): self.pBarWindow = self.builder.get_object("pBarWindow") if self.pBarWindow: self.connect_signal(self.pBarWindow, "delete_event", self.sw_delete_event_cb) + pb_log_expander = self.builder.get_object("pb_log_expander") + pb_log_expander.add(self.log) self.connect_signal(daemon, "analyze-complete", self.on_analyze_complete_cb, self.pBarWindow) self.connect_signal(daemon, "report-done", self.on_report_done_cb) @@ -82,15 +122,10 @@ class ReporterAssistant(): viewer.set_transient_for(self.assistant) vbox = gtk.VBox() viewer.add(vbox) - log_tev = gtk.TextView() - log_tev.set_editable(False) - log_buff = gtk.TextBuffer() - log_buff.set_text(self.updates) - log_sw = gtk.ScrolledWindow() - log_sw.add(log_tev) - log_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - log_tev.set_buffer(log_buff) - vbox.pack_start(log_sw) + log = Log() + for line in self.updates: + log.append_line(line) + vbox.pack_start(log) b_close = gtk.Button(stock=gtk.STOCK_CLOSE) b_close.connect("clicked",lambda *w: viewer.destroy()) vbox.pack_start(b_close, False) @@ -159,17 +194,10 @@ class ReporterAssistant(): gtk.main_quit() def update_cb(self, daemon, message): - self.updates += message - if self.updates[-1] != '\n': - self.updates += '\n' + self.updates.append(message) 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) + self.log.append_line(message) def sw_delete_event_cb(self, widget, event, data=None): if self.timer: @@ -1093,9 +1121,7 @@ class ReporterAssistant(): self.prepare_page_3() self.prepare_page_4() self.prepare_page_5() - self.updates = "" # FIXME don't duplicate the code, move to function - #self.pBar.show() self.show_progress() self.timer = gobject.timeout_add(100, self.progress_update_cb) diff --git a/src/gui/CellRenderers.py b/src/gui/CellRenderers.py deleted file mode 100644 index 155d8ce3..00000000 --- a/src/gui/CellRenderers.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- -import gtk - -class CellTextView(gtk.TextView, gtk.CellEditable): - - __gtype_name__ = "CellTextView" - - def do_editing_done(self, *args): - self.remove_widget() - - def do_remove_widget(self, *args): - pass - - def do_start_editing(self, *args): - pass - - def get_text(self): - text_buffer = self.get_buffer() - bounds = text_buffer.get_bounds() - return text_buffer.get_text(*bounds) - - def set_text(self, text): - self.get_buffer().set_text(text) - - -class MultilineCellRenderer(gtk.CellRendererText): - - __gtype_name__ = "MultilineCellRenderer" - - def __init__(self): - gtk.CellRendererText.__init__(self) - self._in_editor_menu = False - self.old_text = "" - - def _on_editor_focus_out_event(self, editor, event): - if self._in_editor_menu: return - editor.remove_widget() - self.emit("edited", editor.get_data("path"), editor.get_text()) - - def _on_editor_key_press_event(self, editor, event): - if event.state & (gtk.gdk.SHIFT_MASK | gtk.gdk.CONTROL_MASK): return - if event.keyval == gtk.keysyms.Escape: - editor.set_text(self.old_text) - editor.remove_widget() - self.emit("editing-canceled") - - def _on_editor_populate_popup(self, editor, menu): - self._in_editor_menu = True - def on_menu_unmap(menu, self): - self._in_editor_menu = False - menu.connect("unmap", on_menu_unmap, self) - - def do_start_editing(self, event, widget, path, bg_area, cell_area, flags): - editor = CellTextView() - editor.modify_font(self.props.font_desc) - self.old_text = self.props.text - editor.set_text(self.props.text) - editor.set_size_request(cell_area.width, cell_area.height) - editor.set_border_width(min(self.props.xpad, self.props.ypad)) - editor.set_data("path", path) - editor.connect("focus-out-event", self._on_editor_focus_out_event) - editor.connect("key-press-event", self._on_editor_key_press_event) - editor.connect("populate-popup", self._on_editor_populate_popup) - editor.show() - return editor - diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 002b3bc7..61725d6f 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -1,8 +1,8 @@ bin_SCRIPTS = abrt-gui PYTHON_FILES = CCDBusBackend.py CCDumpList.py CCDump.py CC_gui_functions.py \ - CCReporterDialog.py abrt_utils.py \ - CCMainWindow.py CellRenderers.py ABRTExceptions.py \ + abrt_utils.py \ + CCMainWindow.py ABRTExceptions.py \ SettingsDialog.py ABRTPlugin.py PluginList.py PluginSettingsUI.py \ PluginsSettingsDialog.py ConfBackend.py CReporterAssistant.py diff --git a/src/gui/SettingsDialog.py b/src/gui/SettingsDialog.py index e6d30e99..41fb9829 100644 --- a/src/gui/SettingsDialog.py +++ b/src/gui/SettingsDialog.py @@ -27,28 +27,10 @@ class SettingsDialog: self.window = self.builder.get_object("wGlobalSettings") self.builder.get_object("bSaveSettings").connect("clicked", self.on_ok_clicked) self.builder.get_object("bCancelSettings").connect("clicked", self.on_cancel_clicked) - self.builder.get_object("bAddCronJob").connect("clicked", self.on_bAddCronJob_clicked) - - # action plugin list for Cron tab - self.actionPluginsListStore = gtk.ListStore(str, object) - self.actionPluginsListStore.append([_("<b>Select plugin</b>"), None]) - # database plugin list - self.databasePluginsListStore = gtk.ListStore(str, object) - self.databasePluginsListStore.append([_("<b>Select database backend</b>"), None]) - - self.dbcombo = self.builder.get_object("cbDatabase") - self.dbcombo.set_model(self.databasePluginsListStore) - cell = gtk.CellRendererText() - self.dbcombo.pack_start(cell) - self.dbcombo.add_attribute(cell, "markup", 0) # blacklist edit self.builder.get_object("bEditBlackList").connect("clicked", self.on_blacklistEdit_clicked) self.builder.get_object("bOpenGPGPublicKeys").connect("clicked", self.on_GPGKeysEdit_clicked) - self.builder.get_object("bAddAction").connect("clicked", self.on_bAddAction_clicked) - # AnalyzerActionsAndReporters - self.analyzerPluginsListStore = gtk.ListStore(str, object) - self.analyzerPluginsListStore.append([_("<b>Select plugin</b>"), None]) # GPG keys self.wGPGKeys = self.builder.get_object("wGPGKeys") self.GPGKeysListStore = gtk.ListStore(str) @@ -77,18 +59,6 @@ class SettingsDialog: except Exception, e: raise Exception("Comunication with daemon has failed, have you restarted the daemon after update?") - ## hydrate cron jobs: - for key,val in self.settings["Cron"].iteritems(): - # actions are separated by ',' - actions = val.split(',') - self.settings["Cron"][key] = actions - for plugin in self.pluginlist.getActionPlugins(): - it = self.actionPluginsListStore.append([plugin.getName(), plugin]) - for key,val in self.settings["Cron"].iteritems(): - if plugin.getName() in val: - cron_job = (key,it) - self.add_CronJob(cron_job) - self.settings["Cron"][key].remove(plugin.getName()) # hydrate common common = self.settings["Common"] # ensure that all expected keys exist: @@ -96,11 +66,6 @@ class SettingsDialog: common["OpenGPGCheck"] = "no" # check unsigned pkgs too ## gpgcheck self.builder.get_object("cbOpenGPGCheck").set_active(common["OpenGPGCheck"] == 'yes') - ## database - for dbplugin in self.pluginlist.getDatabasePlugins(): - it = self.databasePluginsListStore.append([dbplugin.getName(), dbplugin]) - if common["Database"] == dbplugin.getName(): - self.dbcombo.set_active_iter(it) ## MaxCrashSize self.builder.get_object("sbMaxCrashReportsSize").set_value(float(common["MaxCrashReportsSize"])) ## GPG keys @@ -114,13 +79,6 @@ class SettingsDialog: ## blacklist self.builder.get_object("eBlacklist").set_text(common["BlackList"]) - # hydrate AnalyzerActionsAndReporters - AnalyzerActionsAndReporters = self.settings["AnalyzerActionsAndReporters"] - for analplugin in self.pluginlist.getAnalyzerPlugins(): - it = self.analyzerPluginsListStore.append([analplugin.getName(), analplugin]) - if analplugin.getName() in AnalyzerActionsAndReporters: - action = (AnalyzerActionsAndReporters[analplugin.getName()], it) - self.add_AnalyzerAction(action) def on_bCancelGPGKeys_clicked(self, button): self.wGPGKeys.hide() @@ -147,12 +105,6 @@ class SettingsDialog: def on_cancel_clicked(self, button): self.window.hide() - def on_remove_CronJob_clicked(self, button, job_hbox): - self.removeHBoxWihtChildren(job_hbox) - - def on_remove_Action_clicked(self, button, binding_hbox): - self.removeHBoxWihtChildren(binding_hbox) - def removeHBoxWihtChildren(self, job_hbox): job_hbox.get_parent().remove(job_hbox) for child in job_hbox.get_children(): @@ -237,7 +189,10 @@ class SettingsDialog: self.add_AnalyzerAction() def dehydrate(self): - self.ccdaemon.setSettings(self.settings) + pass + ### looks unused to me. + ### Ok to grep for setSettings and delete after 2011-04-01. + ### self.ccdaemon.setSettings(self.settings) def show(self): self.window.show() diff --git a/src/gui/ccgui.glade b/src/gui/ccgui.glade index 4f8c4f02..c2efa148 100644 --- a/src/gui/ccgui.glade +++ b/src/gui/ccgui.glade @@ -9,7 +9,6 @@ <property name="window_position">center-on-parent</property> <property name="icon_name">abrt</property> <property name="type_hint">dialog</property> - <property name="has_separator">False</property> <property name="program_name">ABRT</property> <property name="version">@VER@</property> <property name="copyright" translatable="yes">(C) 2009, 2010 Red Hat, Inc.</property> @@ -128,6 +127,20 @@ Máirín Duffy <duffy@redhat.com></property> </widget> </child> <child> + <widget class="GtkImageMenuItem" id="miOnlineHelp"> + <property name="label" translatable="yes">Online _Help</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">False</property> + <child internal-child="image"> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-help</property> + </widget> + </child> + </widget> + </child> + <child> <widget class="GtkImageMenuItem" id="miAbout"> <property name="label">gtk-about</property> <property name="visible">True</property> @@ -589,11 +602,34 @@ Máirín Duffy <duffy@redhat.com></property> <property name="homogeneous">True</property> <child> <widget class="GtkButton" id="b_help"> - <property name="label">gtk-help</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="use_stock">True</property> + <child> + <widget class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="yalign">0</property> + <property name="stock">gtk-help</property> + </widget> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes" context="yes">Online _Help</property> + <property name="use_underline">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> </widget> <packing> <property name="padding">10</property> diff --git a/src/gui/progress_window.glade b/src/gui/progress_window.glade index af48ee55..6fae1486 100644 --- a/src/gui/progress_window.glade +++ b/src/gui/progress_window.glade @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <interface> <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy project-wide --> @@ -12,7 +12,6 @@ <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"> @@ -35,23 +34,11 @@ </packing> </child> <child> - <object class="GtkExpander" id="expander1"> + <object class="GtkExpander" id="pb_log_expander"> <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> + <placeholder/> </child> <child type="label"> <object class="GtkLabel" id="lUpdates"> diff --git a/src/gui/settings.glade b/src/gui/settings.glade index b83e6617..9dc1b96f 100644 --- a/src/gui/settings.glade +++ b/src/gui/settings.glade @@ -276,7 +276,7 @@ <object class="GtkTable" id="common_table"> <property name="visible">True</property> <property name="border_width">6</property> - <property name="n_rows">5</property> + <property name="n_rows">4</property> <property name="n_columns">2</property> <property name="column_spacing">12</property> <property name="row_spacing">6</property> @@ -294,32 +294,6 @@ </packing> </child> <child> - <object class="GtkLabel" id="lDatabasePlugin"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes">Database backend: </property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkComboBox" id="cbDatabase"> - <property name="visible">True</property> - </object> - <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> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> <object class="GtkLabel" id="lBlacklist"> <property name="visible">True</property> <property name="xalign">0</property> @@ -348,20 +322,6 @@ </packing> </child> <child> - <object class="GtkLabel" id="lOpenGPGPublicKeys"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes">GPG keys: </property> - </object> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> <object class="GtkSpinButton" id="sbMaxCrashReportsSize"> <property name="visible">True</property> <property name="can_focus">True</property> @@ -414,6 +374,20 @@ </packing> </child> <child> + <object class="GtkLabel" id="lOpenGPGPublicKeys"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">GPG keys: </property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> <object class="GtkHBox" id="gpghbox"> <property name="visible">True</property> <property name="spacing">6</property> @@ -445,8 +419,8 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="y_options">GTK_FILL</property> </packing> </child> @@ -461,241 +435,6 @@ <property name="tab_fill">False</property> </packing> </child> - <child> - <object class="GtkVBox" id="cron_vbox"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkScrolledWindow" id="swCronJobs"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <child> - <object class="GtkViewport" id="vpCronJobs"> - <property name="visible">True</property> - <property name="resize_mode">queue</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkVBox" id="cjvbox1"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkHBox" id="cjhbox1"> - <property name="visible">True</property> - <child> - <object class="GtkLabel" id="lPlugin"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Plugin</b></property> - <property name="use_markup">True</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="lTime"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Time (or period)</b></property> - <property name="use_markup">True</property> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="vbCronJobs"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <placeholder/> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHButtonBox" id="hbuttonboxy1"> - <property name="visible">True</property> - <property name="spacing">12</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="bAddCronJob"> - <property name="label">gtk-add</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="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child type="tab"> - <object class="GtkLabel" id="pCron"> - <property name="visible">True</property> - <property name="label" translatable="yes">Cron</property> - </object> - <packing> - <property name="position">1</property> - <property name="tab_fill">False</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="actions_vbox"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object 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> - <child> - <object class="GtkViewport" id="viewportA1"> - <property name="visible">True</property> - <property name="resize_mode">queue</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkVBox" id="vbox1"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkHBox" id="ahbox1"> - <property name="visible">True</property> - <child> - <object class="GtkLabel" id="lReporter"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Analyzer plugin</b></property> - <property name="use_markup">True</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="lAssociatedActions"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Associated action</b></property> - <property name="use_markup">True</property> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkAlignment" id="action_lbl_align"> - <property name="visible">True</property> - <child> - <placeholder/> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="vbActions"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <placeholder/> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHButtonBox" id="hbuttonbox2"> - <property name="visible">True</property> - <property name="spacing">12</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="bAddAction"> - <property name="label">gtk-add</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="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - <child type="tab"> - <object class="GtkLabel" id="pAnacre"> - <property name="visible">True</property> - <property name="label" translatable="yes">Analyzers, Actions, Reporters</property> - </object> - <packing> - <property name="position">2</property> - <property name="tab_fill">False</property> - </packing> - </child> </object> <packing> <property name="position">0</property> |
