# -*- coding: utf-8 -*- import pygtk pygtk.require("2.0") import gtk #, pango import gtk.glade import pango import sys from CC_gui_functions import * import CellRenderers from ABRTPlugin import PluginInfo from PluginSettingsUI import PluginSettingsUI from PluginList import getPluginInfoList #from CCDumpList import getDumpList, DumpList from abrt_utils import _, log, log1, log2 # FIXME - create method or smth that returns type|editable|content CD_TYPE = 0 CD_EDITABLE = 1 CD_CONTENT = 2 CD_SYS = "s" CD_BIN = "b" CD_TXT = "t" CD_ATT = "a" # response REFRESH = -50 SHOW_LOG = -60 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 self.gladefile = "%s%sreport.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("reporter_dialog") self.window.set_default_size(640, 480) self.window.connect("response", self.on_response, daemon) if parent: self.window.set_transient_for(parent) self.window.set_modal(True) # comment textview self.tvComment = self.wTree.get_widget("tvComment") self.tvComment.connect("focus-in-event", self.on_comment_focus_cb) self.comment_changed = False # "how to reproduce" textview self.tevHowToReproduce = self.wTree.get_widget("tevHowToReproduce") self.how_to_changed = False self.tvReport = self.wTree.get_widget("tvReport") self.reportListStore = gtk.ListStore(str, str, bool, bool, bool) # set filter #self.modelfilter = self.reportListStore.filter_new() #self.modelfilter.set_visible_func(self.filter_reports, None) self.tvReport.set_model(self.reportListStore) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('Item', renderer, text=0) self.tvReport.append_column(column) renderer = CellRenderers.MultilineCellRenderer() renderer.props.editable = True renderer.props.wrap_mode = pango.WRAP_WORD renderer.props.wrap_width = 800 #renderer.props.wrap_mode = pango.WRAP_WORD #renderer.props.wrap_width = 600 column = gtk.TreeViewColumn('Value', renderer, text=1, editable=2) self.tvReport.append_column(column) renderer.connect('edited',self.column_edited,self.reportListStore) # toggle toggle_renderer = gtk.CellRendererToggle() toggle_renderer.set_property('activatable', True) toggle_renderer.connect( 'toggled', self.on_send_toggled, self.reportListStore ) column = gtk.TreeViewColumn('Send', toggle_renderer) column.add_attribute(toggle_renderer, "active", 3) column.add_attribute(toggle_renderer, "visible", 4) self.tvReport.insert_column(column,0) # connect the signals self.tvReport.connect_after("size-allocate", self.on_window_resize) # start with the warning hidden, so it's not visible when there is no rating self.wTree.get_widget("ebErrors").hide() self.wTree.get_widget("bLog").connect("clicked", self.show_log_cb, log) self.hydrate() 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) # print "response_id", response_id if response_id == gtk.RESPONSE_APPLY: if not (self.check_settings(daemon) and self.check_report()): dialog.stop_emission("response") self.wTree.get_widget("bSend").stop_emission("clicked") if response_id == SHOW_LOG: # prevent dialog from quitting the run() 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 not self.comment_changed: widget.set_buffer(gtk.TextBuffer()) self.comment_changed = True def on_window_resize(self, treeview, allocation): # multine support pass #print allocation def column_edited(self, cell, path, new_text, model): # 1 means the second cell model[path][1] = new_text return 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(_("Can't 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: print "cancel" ui.destroy() def check_settings(self, daemon): pluginlist = getPluginInfoList(daemon) reporters = pluginlist.getReporterPlugins() wrong_conf_plugs = [] for reporter in reporters: if reporter.Settings.check() == False: wrong_conf_plugs.append(reporter) #gui_error_message(_("%s is not properly set!\nPlease check the settings and try to report again." % 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(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_NO: # user cancelled reporting return False if response == gtk.RESPONSE_YES: # "user wants to proceed with report" return True return True def hydrate(self): self.editable = [] self.reportListStore.clear() for item in self.report: if item == "Comment": buff = gtk.TextBuffer() comment = _("Brief description how to reproduce this or what you did...") try: if self.report[item][CD_CONTENT]: comment = self.report[item][CD_CONTENT] self.comment_changed = True except Exception, e: pass buff.set_text(comment) self.tvComment.set_buffer(buff) continue if item == "How to reproduce": buff = gtk.TextBuffer() how_to_reproduce = _("") try: if self.report[item][CD_CONTENT]: how_to_reproduce = self.report[item][CD_CONTENT] self.how_to_changed = True except Exception, e: pass buff.set_text(how_to_reproduce) self.tevHowToReproduce.set_buffer(buff) continue # if an backtrace has rating use it if item == "rating": try: package = self.report["package"][CD_CONTENT] # if we don't have package for some reason except: package = None ebErrors = self.wTree.get_widget("ebErrors") fReproducer = self.wTree.get_widget("fReproducer") fComments = self.wTree.get_widget("fComments") lErrors = self.wTree.get_widget("lErrors") bSend = self.wTree.get_widget("bSend") # not usable report if int(self.report[item][CD_CONTENT]) < 3: ebErrors.show() fReproducer.hide() fComments.hide() if package: lErrors.set_markup( _("Reporting disabled because the backtrace is unusable.\nPlease try to install debuginfo manually using command: debuginfo-install %s \nthen use Refresh button to regenerate the backtrace." % package[0:package.rfind('-',0,package.rfind('-'))])) else: lErrors.set_markup(_("The backtrace is unusable, you can't report this!")) bSend.set_sensitive(False) # probably usable 3 elif int(self.report[item][CD_CONTENT]) < 4: ebErrors.show() lErrors.set_markup(_("The backtrace is incomplete, please make sure you provide good steps to reproduce.")) bSend.set_sensitive(True) else: ebErrors.hide() fReproducer.show() fComments.show() bSend.set_sensitive(True) if self.report[item][CD_TYPE] != CD_SYS: # item name 0| value 1| editable? 2| toggled? 3| visible?(attachment)4 if self.report[item][CD_EDITABLE] == 'y': self.editable.append(item) self.row_dict[item] = self.reportListStore.append([item, self.report[item][CD_CONTENT], item in self.editable, True, self.report[item][CD_TYPE] in [CD_ATT,CD_BIN]]) def dehydrate(self): attributes = ["item", "content", "editable", "send", "attachment"] for row in self.reportListStore: rowe = dict(zip(attributes, row)) if not rowe["editable"] and not rowe["attachment"]: self.report[rowe["item"]][CD_CONTENT] = rowe["content"] elif rowe["editable"] and not rowe["attachment"]: self.report[rowe["item"]][CD_CONTENT] = rowe["content"] elif (rowe["attachment"] or (rowe["editable"] and rowe["attachment"])) and rowe["send"]: self.report[rowe["item"]][CD_CONTENT] = rowe["content"] else: del self.report[rowe["item"]] # handle comment if self.comment_changed: buff = self.tvComment.get_buffer() self.report["Comment"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())] else: del self.report["Comment"] # handle how to reproduce if self.how_to_changed: buff = self.tevHowToReproduce.get_buffer() self.report["How to reproduce"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())] else: del self.report["How to reproduce"] def check_report(self): # FIXME: what to do if user press "Not to send BT and then press cancel" # it uncheck the backtrace and let him to edit it, and then user might # not noticed, that he is not sending the BT, so should we warn user about this # or check the BT automatically? attributes = ["item", "content", "editable", "send", "attachment"] for row in self.reportListStore: rowe = dict(zip(attributes, row)) if (rowe["attachment"] or (rowe["editable"] and rowe["attachment"])) and rowe["send"]: result = gui_question_dialog(_("WARNING, you're about to send data which might contain sensitive information.\n" "Do you really want to send %s?\n" % rowe["item"]), self.window) if result == gtk.RESPONSE_NO: row[attributes.index("send")] = False if result in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT): return False self.dehydrate() return True def run(self): result = self.window.run() self.window.destroy() return (result, self.report)