コード例 #1
0
ファイル: tools.py プロジェクト: mhabrnal/gnome-abrt
def load_icon(name=None, gicon=None, scale=1):
    theme = Gtk.IconTheme.get_default()

    icon = None
    if gicon is not None and name is None:
        name = gicon.to_string()
        icon = theme.lookup_by_gicon_for_scale(gicon, 128, scale,
                                        Gtk.IconLookupFlags.FORCE_SIZE)
    elif name is not None and gicon is None:
        icon = theme.lookup_icon_for_scale(name, 128, scale,
                                        Gtk.IconLookupFlags.FORCE_SIZE
                                        | Gtk.IconLookupFlags.FORCE_SYMBOLIC)
    else:
        logging.error("BUG: invalid arguments in load_icon():" \
                      "name={0}, gicon={1}, scale={2}"
                      .format(str(name), str(gicon), str(scale)))
        return None

    if icon is None:
        logging.warning(_("Failed to find icon '{0}'").format(name))
        return None

    try:
        return icon.load_icon()
    #pylint: disable=E0712
    except GLib.Error as ex:
        logging.warning(_("Failed to load icon '{0}': {1}")
                            .format(name, str(ex)))

    return None
コード例 #2
0
def problem_to_storage_values(problem):
    app = problem.get_application()

    if app.name:
        name = app.name
    else:
        name = problem['human_type']

    if name == "kernel" or name.startswith("kernel-"):
        # Translators: if the kernel crashed we display the word "System"
        # instead of "kernel". In this context "System" is like a proper
        # package name, probably a nominative noun.
        name = C_("package name", "System")

    problem_type = problem['type']
    if problem_type == "CCpp":
        # Translators: These are the problem types displayed in the problem
        # list under the application name
        problem_type = _("Application Crash")
    elif problem_type == "vmcore":
        problem_type = _("System Crash")
    elif problem_type == "Kerneloops":
        problem_type = _("System Failure")
    else:
        problem_type = _("Misbehavior")

    return (smart_truncate(name, length=40), fancydate(problem['date_last']),
            problem_type, problem['count'], problem)
コード例 #3
0
ファイル: views.py プロジェクト: jfilak/gnome-abrt
def problem_to_storage_values(problem):
    app = problem.get_application()

    if app.name:
        name = app.name
    else:
        name = problem['human_type']

    if name == "kernel" or name.startswith("kernel-"):
        # Translators: if the kernel crashed we display the word "System"
        # instead of "kernel". In this context "System" is like a proper
        # package name, probably a nominative noun.
        name = C_("package name", "System")

    problem_type = problem['type']
    if problem_type == "CCpp":
        # Translators: These are the problem types displayed in the problem
        # list under the application name
        problem_type = _("Application Crash")
    elif problem_type == "vmcore":
        problem_type = _("System Crash")
    elif problem_type == "Kerneloops":
        problem_type = _("System Failure")
    else:
        problem_type = _("Misbehavior")

    return (smart_truncate(name, length=40),
            fancydate(problem['date_last']),
            problem_type,
            problem['count'],
            problem)
コード例 #4
0
ファイル: tools.py プロジェクト: frafra/gnome-abrt
def load_icon(name=None, gicon=None, scale=1):
    theme = Gtk.IconTheme.get_default()

    icon = None
    if not gicon is None and name is None:
        name = gicon.to_string()
        icon = theme.lookup_by_gicon_for_scale(gicon, 128, scale,
                                        Gtk.IconLookupFlags.FORCE_SIZE)
    elif not name is None and gicon is None:
        icon = theme.lookup_icon_for_scale(name, 128, scale,
                                        Gtk.IconLookupFlags.FORCE_SIZE
                                        | Gtk.IconLookupFlags.FORCE_SYMBOLIC)
    else:
        logging.error("BUG: invalid arguments in load_icon():" \
                      "name={0}, gicon={1}, scale={2}"
                      .format(str(name), str(gicon), str(scale)))
        return None

    if icon is None:
        logging.warning(_("Failed to find icon '{0}'").format(name))
        return None

    try:
        return icon.load_icon()
    #pylint: disable=E0712
    except GLib.Error as ex:
        logging.warning(_("Failed to load icon '{0}': {1}")
                            .format(name, str(ex)))

    return None
コード例 #5
0
ファイル: views.py プロジェクト: solorray/gnome-abrt
    def _get_summary_for_problem_type(self, problem_type):
        if problem_type == 'Kerneloops':
            return _("The system has encountered a problem and recovered.")
        if problem_type == 'vmcore':
            return _(
                "The system has encountered a problem and could not continue.")

        return _(
            "The application encountered a problem and could not continue.")
コード例 #6
0
ファイル: tools.py プロジェクト: mmathesius/gnome-abrt
def fancydate(value, base_date=None):
    """
    Converts a date to a fancy string
    """
    if not base_date:
        base_date = datetime.datetime.now()

    old_date = value
    if base_date < old_date:
        return _('Future')

    tmdt = base_date.date() - old_date.date()

    if tmdt.days == 0:
        return old_date.time().strftime(get_configuration()['T_FMT'])
    elif tmdt.days == 1:
        return _('Yesterday')

    # this week - return a name of a day
    if tmdt.days < base_date.isoweekday():
        return calendar.day_name[base_date.weekday() - tmdt.days]

    if old_date.month == base_date.month and old_date.year == base_date.year:
        # computes a number of calendar weeks (not only 7 days)
        # Note: the offset will never be negative nor zero because
        # negative means the future and 0 means today, these cases
        # have been handled few lines above. The same rule is true
        # for the code below.
        offset = int(round((tmdt.days - base_date.isoweekday()) / 7, 0)) + 1
        if offset == 1:
            return _('Last week')
        # Translators: This message will never be used for less than
        # 2 weeks ago nor for more than one month ago. However, the singular
        # form is necessary for some languages which do not have plural.
        msg = ngettext('{0:d} week ago', '{0:d} weeks ago', offset)
        return msg.format(offset)
    elif old_date.year == base_date.year:
        offset = base_date.month - old_date.month
        if offset == 1:
            return _('Last month')
        # Translators: This message will never be used for less than
        # 2 months ago nor for more than one year ago. See the comment above.
        msg = ngettext('{0:d} month ago', '{0:d} months ago', offset)
        return msg.format(offset)
    else:
        offset = base_date.year - old_date.year
        if offset == 1:
            return _('Last year')
        # Translators: This message will never be used for less than
        # 2 years ago. However, the singular form is necessary for some
        # languages which do not have plural (Chinese, Japanese, Korean)
        # or reuse the singular form for some plural cases (21 in Russian).
        msg = ngettext('{0:d} year ago', '{0:d} years ago', offset)
        return msg.format(offset)
コード例 #7
0
ファイル: tools.py プロジェクト: frafra/gnome-abrt
def fancydate(value, base_date=None):
    """
    Converts a date to a fancy string
    """
    if not base_date:
        base_date = datetime.datetime.now()

    old_date = value
    if base_date < old_date:
        return _('Future')

    tmdt = base_date.date() - old_date.date()

    if tmdt.days == 0:
        return old_date.time().strftime(get_configuration()['T_FMT'])
    elif tmdt.days == 1:
        return _('Yesterday')

    # this week - return a name of a day
    if tmdt.days < base_date.isoweekday():
        return calendar.day_name[base_date.weekday() - tmdt.days]

    if old_date.month == base_date.month and old_date.year == base_date.year:
        # computes a number of calendar weeks (not only 7 days)
        # Note: the offset will never be negative nor zero because
        # negative means the future and 0 means today, these cases
        # have been handled few lines above. The same rule is true
        # for the code below.
        offset = int(round((tmdt.days - base_date.isoweekday())/7, 0)) + 1
        if offset == 1:
            return _('Last week')
        # Translators: This message will never be used for less than
        # 2 weeks ago nor for more than one month ago. However, the singular
        # form is necessary for some languages which do not have plural.
        msg = ngettext('{0:d} week ago', '{0:d} weeks ago', offset)
        return msg.format(offset)
    elif old_date.year == base_date.year:
        offset = base_date.month - old_date.month
        if offset == 1:
            return _('Last month')
        # Translators: This message will never be used for less than
        # 2 months ago nor for more than one year ago. See the comment above.
        msg = ngettext('{0:d} month ago', '{0:d} months ago', offset)
        return msg.format(offset)
    else:
        offset = base_date.year - old_date.year
        if offset == 1:
            return _('Last year')
        # Translators: This message will never be used for less than
        # 2 years ago. However, the singular form is necessary for some
        # languages which do not have plural (Chinese, Japanese, Korean)
        # or reuse the singular form for some plural cases (21 in Russian).
        msg = ngettext('{0:d} year ago', '{0:d} years ago', offset)
        return msg.format(offset)
コード例 #8
0
ファイル: dialogs.py プロジェクト: frafra/gnome-abrt
def show_report_problem_with_abrt():
    wnd_report = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
    wnd_report.set_title(_("Problem description"))
    wnd_report.set_default_size(400, 400)

    wnd_report.vbox = Gtk.VBox.new(False, 0)
    wnd_report.vbox.set_margin_top(5)
    wnd_report.vbox.set_margin_left(5)
    wnd_report.vbox.set_margin_right(5)

    wnd_report.lbl_summary = Gtk.Label.new(_("Summary:"))
    wnd_report.lbl_summary.set_halign(Gtk.Align.START)
    wnd_report.lbl_summary.set_margin_left(3)
    wnd_report.lbl_summary.set_margin_right(3)

    #pylint: disable=E1120
    wnd_report.txe_reason = Gtk.Entry.new()

    #pylint: disable=E1120
    wnd_report.tev = Gtk.TextView.new()
    wnd_report.tev.set_margin_left(3)
    wnd_report.tev.set_margin_right(3)
    wnd_report.tev.set_can_focus(True)
    wnd_report.tev.set_wrap_mode(Gtk.WrapMode.WORD)

    #pylint: disable=E1120
    scrl_wnd = Gtk.ScrolledWindow.new(None, None)
    scrl_wnd.add(wnd_report.tev)

    wnd_report.btn_send = Gtk.Button.new_with_label(_("_Send"))
    wnd_report.btn_send.set_use_underline(True)
    wnd_report.btn_send.connect("clicked", _on_button_send_cb, wnd_report)

    wnd_report.vbox.pack_start(wnd_report.lbl_summary, False, True, 3)
    wnd_report.vbox.pack_start(wnd_report.txe_reason, False, True, 3)
    wnd_report.vbox.pack_start(scrl_wnd, True, True, 5)
    wnd_report.vbox.pack_start(wnd_report.btn_send, False, True, 3)

    wnd_report.add(wnd_report.vbox)

    wnd_report.show_all()

    # Sets text but text is selected :)
    wnd_report.txe_reason.set_text(_("A problem with ABRT"))
    # Unselect text in txe_entry
    wnd_report.txe_reason.set_position(0)

    # Move focus to text view with description of problem
    wnd_report.tev.grab_focus()

    return wnd_report
コード例 #9
0
def show_report_problem_with_abrt():
    wnd_report = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
    wnd_report.set_title(_("Problem description"))
    wnd_report.set_default_size(400, 400)

    wnd_report.vbox = Gtk.VBox.new(False, 0)
    wnd_report.vbox.set_margin_top(5)
    wnd_report.vbox.set_margin_left(5)
    wnd_report.vbox.set_margin_right(5)

    wnd_report.lbl_summary = Gtk.Label.new(_("Summary:"))
    wnd_report.lbl_summary.set_halign(Gtk.Align.START)
    wnd_report.lbl_summary.set_margin_left(3)
    wnd_report.lbl_summary.set_margin_right(3)

    #pylint: disable=E1120
    wnd_report.txe_reason = Gtk.Entry.new()

    #pylint: disable=E1120
    wnd_report.tev = Gtk.TextView.new()
    wnd_report.tev.set_margin_left(3)
    wnd_report.tev.set_margin_right(3)
    wnd_report.tev.set_can_focus(True)
    wnd_report.tev.set_wrap_mode(Gtk.WrapMode.WORD)

    #pylint: disable=E1120
    scrl_wnd = Gtk.ScrolledWindow.new(None, None)
    scrl_wnd.add(wnd_report.tev)

    wnd_report.btn_send = Gtk.Button.new_with_label(_("_Send"))
    wnd_report.btn_send.set_use_underline(True)
    wnd_report.btn_send.connect("clicked", _on_button_send_cb, wnd_report)

    wnd_report.vbox.pack_start(wnd_report.lbl_summary, False, True, 3)
    wnd_report.vbox.pack_start(wnd_report.txe_reason, False, True, 3)
    wnd_report.vbox.pack_start(scrl_wnd, True, True, 5)
    wnd_report.vbox.pack_start(wnd_report.btn_send, False, True, 3)

    wnd_report.add(wnd_report.vbox)

    wnd_report.show_all()

    # Sets text but text is selected :)
    wnd_report.txe_reason.set_text(_("A problem with ABRT"))
    # Unselect text in txe_entry
    wnd_report.txe_reason.set_position(0)

    # Move focus to text view with description of problem
    wnd_report.tev.grab_focus()

    return wnd_report
コード例 #10
0
ファイル: views.py プロジェクト: hadess/gnome-abrt
        def __init__(self):
            builder = None
            # try to load the glade from git at first step
            ui_files = ['./src/gnome_abrt/oops.glade',
                        GNOME_ABRT_UI_DIR + '/oops.glade']
            for glade_file in ui_files:
                if os.path.exists(glade_file):
                    builder = Gtk.Builder()
                    builder.set_translation_domain(GETTEXT_PROGNAME)
                    try:
                        builder.add_from_file(filename=glade_file)
                    #pylint: disable=E0712
                    except GObject.GError as ex:
                        builder = None
                        logging.debug("Failed to load UI file: '{0}': {1}"
                                .format(glade_file, str(ex)))
                    else:
                        break
                else:
                    logging.debug("UI file does not exist: '{0}'"
                            .format(glade_file))

            if builder is None:
                raise RuntimeError(_("Failed to load UI definition"))

            self._builder = builder

            self.wnd_main = builder.get_object('wnd_main')
            self.gr_main_layout = builder.get_object('gr_main_layout')
            self.ls_problems = builder.get_object('ls_problems')
            self.lbl_reason = builder.get_object('lbl_reason')
            self.lbl_summary = builder.get_object('lbl_summary')
            self.lbl_app_name_value = builder.get_object('lbl_app_name_value')
            self.lbl_app_version_value = builder.get_object(
                    'lbl_app_version_value')
            self.lbl_detected_value = builder.get_object('lbl_detected_value')
            self.lbl_reported = builder.get_object('lbl_reported')
            self.lbl_reported_value = builder.get_object('lbl_reported_value')
            self.lbl_repots = builder.get_object('lbl_reports')
            self.tv_problems = builder.get_object('tv_problems')
            self.tvs_problems = builder.get_object('tvs_problems')
            self.img_app_icon = builder.get_object('img_app_icon')
            self.nb_problem_layout = builder.get_object('nb_problem_layout')
            self.btn_delete = builder.get_object('btn_delete')
            self.btn_report = builder.get_object('btn_report')
            self.btn_detail = builder.get_object('btn_detail')
            self.se_problems = builder.get_object('se_problems')
            self.chb_all_problems = builder.get_object('chb_all_problems')
            self.vbx_links = builder.get_object('vbx_links')
            self.vbx_problem_messages = builder.get_object(
                    'vbx_problem_messages')
            self.gac_report = builder.get_object('gac_report')
            self.gac_delete = builder.get_object('gac_delete')
            self.gac_open_directory = builder.get_object('gac_open_directory')
            self.gac_copy_id = builder.get_object('gac_copy_id')
            self.gac_search = builder.get_object('gac_search')
            self.menu_problem_item = builder.get_object('menu_problem_item')
            self.menu_multiple_problems = builder.get_object(
                    'menu_multiple_problems')
            self.ag_accelerators = builder.get_object('ag_accelerators')
コード例 #11
0
ファイル: dbus_problems.py プロジェクト: clockfort/gnome-abrt
    def __init__(self, mainloop=None):
        super(DBusProblemSource, self).__init__()

        self._mainloop = mainloop
        if not self._mainloop:
            self._mainloop = DBusGMainLoop()

        self._bus = None
        self._proxy = None
        self._interface = None
        self._connect_to_problems_bus()

        try:
            self._bus.add_signal_receiver(self._on_new_problem,
                    signal_name=ABRTD_DBUS_SIGNAL, path=ABRTD_DBUS_PATH)
        except dbus.exceptions.DBusException as ex:
            logging.warning(
        _("Can't add receiver of signal '{0}'on DBus system path '{1}': {2}")
                      .format(ABRTD_DBUS_SIGNAL, ABRTD_DBUS_PATH, ex.message))

        class ConfigObserver():
            def __init__(self, source):
                self.source = source

            #pylint: disable=W0613
            def option_updated(self, conf, option):
                if option == "all_problems":
                    self.source.refresh()

        conf = config.get_configuration()
        conf.set_watch("all_problems", ConfigObserver(self))
コード例 #12
0
ファイル: dbus_problems.py プロジェクト: hadess/gnome-abrt
    def _get_problems(self):
        prblms = []
        try:
            prblms = self._send_dbus_message(self._driver.get_problems_method)
        except dbus.exceptions.DBusException as ex:
            logging.warning(_("Can't get list of problems from DBus service: {0!s}").format(ex))

        return (str(pid) for pid in prblms)
コード例 #13
0
    def _connect_to_problems_bus(self):
        # I can't find any description of raised exceptions
        self._bus = dbus.SystemBus(private=True, mainloop=self._mainloop)

        try:
            self._proxy = self._bus.get_object(BUS_NAME, BUS_PATH)
        except dbus.exceptions.DBusException as ex:
            raise errors.UnavailableSource(self, False,
                    _("Can't connect to DBus system bus '{0}' path '{1}': {2}")
                        .format(BUS_NAME, BUS_PATH, ex))

        try:
            self._interface = dbus.Interface(self._proxy, BUS_IFACE)
        except dbus.exceptions.DBusException as ex:
            raise errors.UnavailableSource(self, False,
                _("Can't get interface '{0}' on path '{1}' in bus '{2}': {3}")
                    .format(BUS_IFACE, BUS_PATH, BUS_NAME, ex))
コード例 #14
0
ファイル: views.py プロジェクト: clockfort/gnome-abrt
def problem_to_storage_values(problem):
    # not localizable, it is a format for tree view column
    app = problem.get_application()
    return ["{0!s}\n{1!s}".format(app.name or _("N/A"),
                                  problem['type'] or ""),
            "{0!s}\n{1!s}".format(fancydate(problem['date']),
                                  problem['count']),
            problem]
コード例 #15
0
    def _get_problems(self):
        prblms = []
        try:
            prblms = self._send_dbus_message(self._driver.get_problems_method)
        except dbus.exceptions.DBusException as ex:
            logging.warning(
                _("Can't get list of problems from DBus service: {0!s}").
                format(ex))

        return (str(pid) for pid in prblms)
コード例 #16
0
    def _disable_on_max_watches(self, ex, directory):
        self._disabled = True
        logging.debug("Could not add inotify for directory '{0}': '{1}'"
                            .format(directory, ex.message))
        logging.warning(
_("You have probably reached inotify's limit on the number of watches in '{0}'."
" The limit can be increased by proper configuration of inotify. For more "
"details see man inotify(7). This event causes that you will not be notified "
"about changes in problem data happening outside of this application. This "
"event do not affect any other functionality.").format(self._directory))
コード例 #17
0
    def delete_problem(self, problem_id):
        if not self._delete_problem(problem_id):
            return

        try:
            self._remove_from_cache(problem_id)
        except ValueError as ex:
            logging.warning(_('Not found in cache but deleted: {0}'), ex)
            self._cache = None
            self.notify()
コード例 #18
0
 def _delete_problem(self, problem_id):
     try:
         self._send_dbus_message(
             lambda iface, *args: iface.DeleteProblem(*args), [problem_id])
         return True
     except dbus.exceptions.DBusException as ex:
         self._driver.on_dbus_exception(problem_id, ex)
         logging.warning(
             _("Can't delete problem over DBus service: {0!s}").format(ex))
         return False
コード例 #19
0
    def _connect_to_problems_bus(self):
        # I can't find any description of raised exceptions
        self._bus = dbus.SystemBus(private=True, mainloop=self._mainloop)

        try:
            self._proxy = self._bus.get_object(BUS_NAME, BUS_PATH)
        except dbus.exceptions.DBusException as ex:
            raise errors.UnavailableSource(
                self, False,
                _("Can't connect to DBus system bus '{0}' path '{1}': {2}").
                format(BUS_NAME, BUS_PATH, ex))

        try:
            self._interface = dbus.Interface(self._proxy, BUS_IFACE)
        except dbus.exceptions.DBusException as ex:
            raise errors.UnavailableSource(
                self, False,
                _("Can't get interface '{0}' on path '{1}' in bus '{2}': {3}").
                format(BUS_IFACE, BUS_PATH, BUS_NAME, ex))
コード例 #20
0
ファイル: views.py プロジェクト: frafra/gnome-abrt
        def __init__(self):
            builder = None
            # try to load the glade from git at first step
            ui_files = ["./src/gnome_abrt/oops.glade", GNOME_ABRT_UI_DIR + "/oops.glade"]
            for glade_file in ui_files:
                if os.path.exists(glade_file):
                    builder = Gtk.Builder()
                    builder.set_translation_domain(GETTEXT_PROGNAME)
                    try:
                        builder.add_from_file(filename=glade_file)
                    # pylint: disable=E0712
                    except GObject.GError as ex:
                        builder = None
                        logging.debug("Failed to load UI file: '{0}': {1}".format(glade_file, str(ex)))
                    else:
                        break
                else:
                    logging.debug("UI file does not exist: '{0}'".format(glade_file))

            if builder is None:
                raise RuntimeError(_("Failed to load UI definition"))

            self._builder = builder

            self.wnd_main = builder.get_object("wnd_main")
            self.box_window = builder.get_object("box_window")
            self.box_sources_switcher = builder.get_object("box_sources_switcher")
            self.lbl_reason = builder.get_object("lbl_reason")
            self.lbl_summary = builder.get_object("lbl_summary")
            self.lbl_app_name_value = builder.get_object("lbl_app_name_value")
            self.lbl_app_version_value = builder.get_object("lbl_app_version_value")
            self.lbl_detected_value = builder.get_object("lbl_detected_value")
            self.lbl_reported = builder.get_object("lbl_reported")
            self.lbl_reported_value = builder.get_object("lbl_reported_value")
            self.lbl_repots = builder.get_object("lbl_reports")
            self.lb_problems = builder.get_object("lb_problems")
            self.img_app_icon = builder.get_object("img_app_icon")
            self.nb_problem_layout = builder.get_object("nb_problem_layout")
            self.btn_delete = builder.get_object("btn_delete")
            self.btn_report = builder.get_object("btn_report")
            self.btn_detail = builder.get_object("btn_detail")
            self.se_problems = builder.get_object("se_problems")
            self.search_bar = builder.get_object("search_bar")
            self.chb_all_problems = builder.get_object("chb_all_problems")
            self.vbx_links = builder.get_object("vbx_links")
            self.vbx_problem_messages = builder.get_object("vbx_problem_messages")
            self.gac_report = builder.get_object("gac_report")
            self.gac_delete = builder.get_object("gac_delete")
            self.gac_open_directory = builder.get_object("gac_open_directory")
            self.gac_copy_id = builder.get_object("gac_copy_id")
            self.gac_search = builder.get_object("gac_search")
            self.menu_problem_item = builder.get_object("menu_problem_item")
            self.menu_multiple_problems = builder.get_object("menu_multiple_problems")
            self.ag_accelerators = builder.get_object("ag_accelerators")
            self.header_bar = None
コード例 #21
0
ファイル: dialogs.py プロジェクト: frafra/gnome-abrt
def _on_button_send_cb(button, dialog):
    buf = dialog.tev.get_buffer()
    it_start = buf.get_start_iter()
    it_end = buf.get_end_iter()
    description = buf.get_text(it_start, it_end, False)

    if len(description) < 10:
        _show_error_dialog(dialog,
                _("The description of problem is too short"),
                _("In order to get more useful reports we "
                    "do not accept reports with the description "
                    "shorter than 10 letters."))

        dialog.tev.grab_focus()
        return

    summary = dialog.txe_reason.get_text()
    if len(summary) < 10:
        _show_error_dialog(dialog,
                _("The summary of problem is too short"),
                _("In order to get more useful reports we "
                    "do not accept reports with the summary "
                    "shorter than 10 letters."))

        dialog.txe_reason.grab_focus()
        dialog.txe_reason.set_position(len(summary))
        return

    dialog.destroy()

    report = problem_data()
    report.add("reason", summary)
    report.add("comment", description)
    report.add("component", gnome_abrt.PACKAGE)
    report.add("package",
            "{0}-{1}".format(gnome_abrt.PACKAGE, gnome_abrt.VERSION))

    report.add_basics()
    report.add("duphash", report.get("uuid")[0])


    report_problem_in_memory(report, LIBREPORT_NOWAIT)
コード例 #22
0
ファイル: dbus_problems.py プロジェクト: jfilak/gnome-abrt
 def chown_problem(self, problem_id):
     try:
         self._send_dbus_message(
                 lambda iface, *params: iface.ChownProblemDir(*params),
                 problem_id)
         return True
     except dbus.exceptions.DBusException as ex:
         logging.warning(
                 _("Can't chown problem '{0}' over DBus service: {1!s}")
                 .format(problem_id, ex))
         return False
コード例 #23
0
ファイル: dbus_problems.py プロジェクト: jfilak/gnome-abrt
 def _delete_problem(self, problem_id):
     try:
         self._send_dbus_message(
             lambda iface, *args: iface.DeleteProblem(*args), [problem_id])
         return True
     except dbus.exceptions.DBusException as ex:
         self._driver.on_dbus_exception(problem_id, ex)
         logging.warning(
                 _("Can't delete problem over DBus service: {0!s}")
                     .format(ex))
         return False
コード例 #24
0
ファイル: problems.py プロジェクト: clockfort/gnome-abrt
    def delete_problem(self, problem_id):
        if not self._delete_problem(problem_id):
            return

        try:
            self._remove_from_cache(problem_id)
        except ValueError as ex:
            logging.warning(_('Not found in cache but deleted: {0}'),
                    ex.message)
            self._cache = None
            self.notify()
コード例 #25
0
 def chown_problem(self, problem_id):
     try:
         self._send_dbus_message(
             lambda iface, *params: iface.ChownProblemDir(*params),
             problem_id)
         return True
     except dbus.exceptions.DBusException as ex:
         logging.warning(
             _("Can't chown problem '{0}' over DBus service: {1!s}").format(
                 problem_id, ex))
         return False
コード例 #26
0
def _on_button_send_cb(button, dialog):
    buf = dialog.tev.get_buffer()
    it_start = buf.get_start_iter()
    it_end = buf.get_end_iter()
    description = buf.get_text(it_start, it_end, False)

    if len(description) < 10:
        _show_error_dialog(
            dialog, _("The description of problem is too short"),
            _("In order to get more useful reports we "
              "do not accept reports with the description "
              "shorter than 10 letters."))

        dialog.tev.grab_focus()
        return

    summary = dialog.txe_reason.get_text()
    if len(summary) < 10:
        _show_error_dialog(
            dialog, _("The summary of problem is too short"),
            _("In order to get more useful reports we "
              "do not accept reports with the summary "
              "shorter than 10 letters."))

        dialog.txe_reason.grab_focus()
        dialog.txe_reason.set_position(len(summary))
        return

    dialog.destroy()

    report = problem_data()
    report.add("reason", summary)
    report.add("comment", description)
    report.add("component", gnome_abrt.PACKAGE)
    report.add("package", "{0}-{1}".format(gnome_abrt.PACKAGE,
                                           gnome_abrt.VERSION))

    report.add_basics()
    report.add("duphash", report.get("uuid")[0])

    report_problem_in_memory(report, LIBREPORT_NOWAIT)
コード例 #27
0
ファイル: problems.py プロジェクト: clockfort/gnome-abrt
 def delete(self):
     # TODO : weird?? the assignemt can be moved
     self._deleted = True
     try:
         self.source.delete_problem(self.problem_id)
     except GnomeAbrtError as ex:
         logging.warning(_("Can't delete problem '{0}': '{1}'")
                             .format(self.problem_id, ex.message))
         self._deleted = False
     except Exception as ex:
         self._deleted = False
         raise
コード例 #28
0
ファイル: problems.py プロジェクト: clockfort/gnome-abrt
 def process_new_problem_id(self, problem_id):
     try:
         if self._problem_is_in_cache(problem_id):
             prblm = self._cache[self._cache.index(problem_id)]
             prblm.refresh()
         else:
             prblm = self._create_new_problem(problem_id)
             self._insert_to_cache(prblm)
             self.notify(ProblemSource.NEW_PROBLEM, prblm)
     except UnavailableSource as ex:
         logging.warning(_("Source failed on processing of '{0}': {1}")
                 .format(problem_id, ex.message))
コード例 #29
0
ファイル: views.py プロジェクト: frafra/gnome-abrt
def problem_to_storage_values(problem):
    app = problem.get_application()

    if app.name:
        name = app.name
    else:
        name = problem["human_type"]

    if name == "kernel":
        name = _("System")

    return (smart_truncate(name, length=40), fancydate(problem["date_last"]), problem["count"], problem)
コード例 #30
0
ファイル: views.py プロジェクト: solorray/gnome-abrt
    def _get_reason_for_problem_type(self, application, problem_type,
                                     human_type):
        if problem_type == 'Kerneloops':
            return _("Unexpected system error")
        if problem_type == 'vmcore':
            return _("Fatal system failure")

        if application.name:
            return _("{0} quit unexpectedly").format(application.name)

        # Translators: If application name is unknown,
        # display neutral header "'Type' problem has been detected".
        # Examples:
        #  Kerneloops problem has been detected
        #  C/C++ problem has been detected
        #  Python problem has been detected
        #  Ruby problem has been detected
        #  VMCore problem has been detected
        #  AVC problem has been detected
        #  Java problem has been detected
        return _("{0} problem has been detected").format(human_type)
コード例 #31
0
 def _disable_on_max_watches(self, ex, directory):
     self._disabled = True
     logging.debug(
         "Could not add inotify for directory '{0}': '{1}'".format(
             directory, ex))
     logging.warning(
         _("You have probably reached inotify's limit on the number of watches in '{0}'."
           " The limit can be increased by proper configuration of inotify. For more "
           "details see man inotify(7). This event causes that you will not be notified "
           "about changes in problem data happening outside of this application. This "
           "event do not affect any other functionality.").format(
               self._directory))
コード例 #32
0
def problem_to_storage_values(problem):
    app = problem.get_application()

    if app.name:
        name = app.name
    else:
        name = problem['human_type']

    if name == "kernel":
        name = _("System")

    return (smart_truncate(name, length=40), fancydate(problem['date_last']),
            problem['count'], problem)
コード例 #33
0
    def get_items(self, problem_id, *args):
        info = {}

        if len(args) != 0:
            try:
                info = self._send_dbus_message(
                    lambda iface, *params: iface.GetInfo(*params), problem_id,
                    args)
            except dbus.exceptions.DBusException as ex:
                self._driver.on_dbus_exception(problem_id, ex)
                logging.warning(
                    _("Can't get problem data from DBus service: {0!s}").
                    format(ex))

        return info
コード例 #34
0
ファイル: dbus_problems.py プロジェクト: jfilak/gnome-abrt
    def get_items(self, problem_id, *args):
        info = {}

        if len(args) != 0:
            try:
                info = self._send_dbus_message(
                        lambda iface, *params: iface.GetInfo(*params),
                        problem_id, args)
            except dbus.exceptions.DBusException as ex:
                self._driver.on_dbus_exception(problem_id, ex)
                logging.warning(
                        _("Can't get problem data from DBus service: {0!s}")
                            .format(ex))

        return info
コード例 #35
0
ファイル: dbus_problems.py プロジェクト: clockfort/gnome-abrt
    def _delete_problem(self, problem_id):
        try:
            self._send_dbus_message(
                #pylint: disable=W0142
                lambda iface, *args: iface.DeleteProblem(*args), [problem_id])
            return True
        except dbus.exceptions.DBusException as ex:
            if ex.get_dbus_name() in ["org.freedesktop.problems.AuthFailure",
                                "org.freedesktop.problems.InvalidProblemDir"]:
                self._remove_from_cache(problem_id)
                raise errors.InvalidProblem(problem_id, ex.message)

            logging.warning(
                    _("Can't delete problem over DBus service: {0!s}")
                        .format(ex.message))
            return False
コード例 #36
0
ファイル: views.py プロジェクト: hadess/gnome-abrt
def problem_to_storage_values(problem):
    # not localizable, it is a format for tree view column
    app = problem.get_application()

    if app.name:
        name = app.name
    else:
        name = problem['human_type']

    if name == "kernel":
        name = _("System")

    return ["{0!s}\n".format(smart_truncate(name, length=40)),
            "{0!s}\n{1!s}".format(fancydate(problem['date_last']),
                                  problem['count']),
            problem]
コード例 #37
0
    def get_items(self, problem_id, *args):
        if len(args) == 0:
            return {}

        dd = report.dd_opendir(problem_id, report.DD_OPEN_READONLY)
        if not dd:
            raise errors.InvalidProblem(problem_id,
                        _("Can't open directory: '{0}'").format(problem_id))

        items = {}
        for field_name in args:
            value = dd.load_text(field_name,
    report.DD_FAIL_QUIETLY_ENOENT | report.DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE)
            if value:
                items[field_name] = value

        dd.close()

        return items
コード例 #38
0
ファイル: dbus_problems.py プロジェクト: clockfort/gnome-abrt
    def _get_problems(self):
        conf = config.get_configuration()

        prblms = []

        try:
            if conf['all_problems']:
                prblms = self._send_dbus_message(
                        #pylint: disable=W0142
                        lambda iface, *args: iface.GetAllProblems(*args))
            else:
                prblms  = self._send_dbus_message(
                        #pylint: disable=W0142
                        lambda iface, *args: self._interface.GetProblems(*args))
        except dbus.exceptions.DBusException as ex:
            logging.warning(
                    _("Can't get list of problems from DBus service: {0!s}")
                        .format(ex.message))

        return (str(pid) for pid in prblms)
コード例 #39
0
    def get_items(self, problem_id, *args):
        if not args:
            return {}

        dd = report.dd_opendir(problem_id, report.DD_OPEN_READONLY)
        if not dd:
            raise errors.InvalidProblem(
                problem_id,
                _("Can't open directory: '{0}'").format(problem_id))

        items = {}
        for field_name in args:
            value = dd.load_text(
                field_name, report.DD_FAIL_QUIETLY_ENOENT
                | report.DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE)
            if value:
                items[field_name] = value

        dd.close()

        return items
コード例 #40
0
    def __init__(self, driverclass, mainloop=None):
        super(DBusProblemSource, self).__init__()

        self._mainloop = mainloop
        if not self._mainloop:
            self._mainloop = DBusGMainLoop()

        self._bus = None
        self._proxy = None
        self._interface = None
        self._connect_to_problems_bus()

        try:
            self._bus.add_signal_receiver(self._on_new_problem,
                    signal_name=ABRTD_DBUS_SIGNAL, path=ABRTD_DBUS_PATH)
        except dbus.exceptions.DBusException as ex:
            logging.warning(
        _("Can't add receiver of signal '{0}'on DBus system path '{1}': {2}")
                      .format(ABRTD_DBUS_SIGNAL, ABRTD_DBUS_PATH, ex))

        self._driver = driverclass(self)
コード例 #41
0
ファイル: dbus_problems.py プロジェクト: clockfort/gnome-abrt
    def get_items(self, problem_id, *args):
        info = {}

        if len(args) != 0:
            try:
                info = self._send_dbus_message(
                        #pylint: disable=W0142
                        lambda iface, *params: iface.GetInfo(*params),
                        problem_id, args)
            except dbus.exceptions.DBusException as ex:
                if ex.get_dbus_name() in [
                                  "org.freedesktop.problems.AuthFailure",
                                  "org.freedesktop.problems.InvalidProblemDir"]:
                    self._remove_from_cache(problem_id)
                    raise errors.InvalidProblem(problem_id, ex.message)

                logging.warning(
                        _("Can't get problem data from DBus service: {0!s}")
                            .format(ex.message))

        return info
コード例 #42
0
ファイル: views.py プロジェクト: clockfort/gnome-abrt
    def _set_problem(self, problem):
        try:
            self.selected_problem = problem

            sensitive_btn = problem is not None
            self._builder.btn_delete.set_sensitive(sensitive_btn)
            self._builder.btn_report.set_sensitive(
                    sensitive_btn and not problem['not-reportable'] )
            self._builder.vbx_links.foreach(
                    lambda w, u: w.destroy(), None)
            self._builder.vbx_problem_messages.foreach(
                    lambda w, u: w.destroy(), None)

            if problem:
                self._builder.nb_problem_layout.set_current_page(0)
                app = problem['application']
                self._builder.lbl_summary.set_text(problem['reason'] or "")
                self._builder.lbl_app_name_value.set_text(app.name or _("N/A"))
                self._builder.lbl_reason.set_text("{0} {1}".format(
                            app.name or _("N/A"), _(' crashed').strip()))
                self._builder.lbl_app_version_value.set_text(
                            problem['package'] or "")

                if app.icon:
                    self._builder.img_app_icon.set_from_pixbuf(app.icon)
                else:
                    self._builder.img_app_icon.clear()

                if problem['is_reported']:
                    self._builder.lbl_reported_value.set_text(_('yes'))
                    self._show_problem_links(problem['submission'])
                else:
                    self._builder.lbl_reported_value.set_text(_('no'))

                if problem['not-reportable']:
                    self._show_problem_message(problem['not-reportable'])
                elif (not problem['is_reported']
                        or not any((s.title == "Bugzilla"
                                for s in problem['submission']))):
                    self._show_problem_message(
    _("This problem hasn't been reported to <i>Bugzilla</i> yet,"
        "our developers maybe need more information to sort out the problem.\n"
        "Please consider <b>reporting it</b>, you may help them. Thank you."))
            else:
                self._builder.nb_problem_layout.set_current_page(1)
        except errors.InvalidProblem as ex:
            self._remove_problem_from_storage(ex.problem_id)
            logging.debug(ex.message)
コード例 #43
0
    def __init__(self, driverclass, mainloop=None):
        super(DBusProblemSource, self).__init__()

        self._mainloop = mainloop
        if not self._mainloop:
            self._mainloop = DBusGMainLoop()

        self._bus = None
        self._proxy = None
        self._interface = None
        self._connect_to_problems_bus()

        try:
            self._bus.add_signal_receiver(self._on_new_problem,
                                          signal_name=ABRTD_DBUS_SIGNAL,
                                          path=ABRTD_DBUS_PATH)
        except dbus.exceptions.DBusException as ex:
            logging.warning(
                _("Can't add receiver of signal '{0}'on DBus system path '{1}': {2}"
                  ).format(ABRTD_DBUS_SIGNAL, ABRTD_DBUS_PATH, ex))

        self._driver = driverclass(self)
コード例 #44
0
def fancydate(value, base_date=None):
    """
    Converts a date to a fancy string
    """
    if not base_date:
        base_date = datetime.datetime.now()

    old_date = value
    if base_date < old_date:
        return _('Future')

    tmdt = base_date.date() - old_date.date()

    if tmdt.days == 0:
        return old_date.time().strftime(get_configuration()['T_FMT'])
    elif tmdt.days == 1:
        return _('Yesterday')

    # this week - return a name of a day
    if tmdt.days < base_date.isoweekday():
        return calendar.day_name[base_date.weekday() - tmdt.days]

    if old_date.month == base_date.month and old_date.year == base_date.year:
        # computes a number of calendar weeks (not only 7 days)
        offset = int(round((tmdt.days - base_date.isoweekday()) / 7, 0)) + 1
        name = _('week')
    elif old_date.year == base_date.year:
        offset = base_date.month - old_date.month
        name = _('month')
    else:
        offset = base_date.year - old_date.year
        name = _('year')

    if offset == 1:
        return _("Last {0!s}").format(name)

    return _("{0:d} {1!s}s ago").format(offset, name)
コード例 #45
0
ファイル: tools.py プロジェクト: clockfort/gnome-abrt
def fancydate(value, base_date=None):
    """
    Converts a date to a fancy string
    """
    if not base_date:
        base_date = datetime.datetime.now()

    old_date = value
    if base_date < old_date:
        return _('Future')

    tmdt = base_date.date() - old_date.date()

    if tmdt.days == 0:
        return old_date.time().strftime(locale.nl_langinfo(locale.T_FMT))
    elif tmdt.days == 1:
        return _('Yesterday')

    # this week - return a name of a day
    if tmdt.days < base_date.isoweekday():
        return calendar.day_name[base_date.weekday() - tmdt.days]

    if old_date.month == base_date.month and old_date.year == base_date.year:
        # computes a number of calendar weeks (not only 7 days)
        offset = int(round((tmdt.days - base_date.isoweekday())/7, 0)) + 1
        name = _('week')
    elif old_date.year == base_date.year:
        offset = base_date.month - old_date.month
        name = _('month')
    else:
        offset = base_date.year - old_date.year
        name = _('year')

    if offset == 1:
        return _("Last {0!s}").format(name)

    return _("{0:d} {1!s}s ago").format(offset, name)
コード例 #46
0
ファイル: views.py プロジェクト: solorray/gnome-abrt
    def _set_problem(self, problem):
        def destroy_links(widget, _):
            if widget != self.lbl_reported_value:
                widget.destroy()

        self.selected_problem = problem

        action_enabled = problem is not None

        self.lookup_action('delete').set_enabled(action_enabled)
        self.lookup_action('report').set_enabled(
            action_enabled and not problem['not-reportable'])

        self.vbx_links.foreach(destroy_links, None)
        self.vbx_problem_messages.foreach(lambda w, u: w.destroy(), None)

        if not problem:
            self.nb_problem_layout.set_visible_child(
                self.vbx_empty_page if self._source else self.
                vbx_no_source_page)

            return

        self.nb_problem_layout.set_visible_child(self.gd_problem_info)

        app = problem['application']

        self.lbl_reason.set_text(
            self._get_reason_for_problem_type(app, problem['type'],
                                              problem['human_type']))
        self.lbl_summary.set_text(
            self._get_summary_for_problem_type(problem['type']))

        # Translators: package name not available
        self.lbl_app_name_value.set_text(problem['package_name'] or _("N/A"))
        # Translators: package version not available
        self.lbl_app_version_value.set_text(problem['package_version']
                                            or _("N/A"))
        self.lbl_detected_value.set_text(
            humanize.naturaltime(datetime.datetime.now() - problem['date']))
        self.lbl_detected_value.set_tooltip_text(problem['date'].strftime(
            config.get_configuration()['D_T_FMT']))

        theme = Gtk.IconTheme.get_default()
        scale = self.img_app_icon.get_scale_factor()
        style_context = self.img_app_icon.get_style_context()

        style_context.remove_class(Gtk.STYLE_CLASS_DIM_LABEL)

        pixbuf = None

        if app.icon:
            icon_info = theme.lookup_by_gicon_for_scale(
                app.icon, 128, scale, Gtk.IconLookupFlags.FORCE_SIZE)
            try:
                pixbuf = icon_info.load_icon() if icon_info else None
            except GLib.Error as ex:
                logging.warning(
                    'Failed to load default icon for {}: {}'.format(
                        app.name, ex))

        if not pixbuf:
            try:
                pixbuf = theme.load_icon_for_scale(
                    'system-run-symbolic', 128, scale,
                    (Gtk.IconLookupFlags.FORCE_SIZE
                     | Gtk.IconLookupFlags.FORCE_SYMBOLIC))

                style_context.add_class(Gtk.STYLE_CLASS_DIM_LABEL)
            except GLib.Error as ex:
                logging.warning(
                    'Failed to load system-run-symbolic: {}'.format(ex))

        if pixbuf:
            surface = Gdk.cairo_surface_create_from_pixbuf(
                pixbuf, scale, self.img_app_icon.get_window())
            self.img_app_icon.set_from_surface(surface)
        else:
            self.img_app_icon.clear()

        self.lbl_reported_value.show()
        self.lbl_reported.set_text(_("Reported"))
        if problem['not-reportable']:
            self.lbl_reported_value.set_text(_('cannot be reported'))

            self._show_problem_links(problem['submission'])
            self._show_problem_message(problem['not-reportable'])
        elif problem['is_reported']:
            if self._show_problem_links(problem['submission']):
                self.lbl_reported.set_text(_("Reports"))
                self.lbl_reported_value.hide()

                if not any(
                    (s.name == "Bugzilla" for s in problem['submission'])):
                    self._show_problem_message(
                        _("This problem has been reported, but a <i>Bugzilla</i> ticket has not"
                          " been opened. Our developers may need more information to fix the problem.\n"
                          "Please consider also <b>reporting it</b> to Bugzilla in"
                          " order to provide that. Thank you."))
            else:
                # Translators: Displayed after 'Reported' if a problem
                # has been reported but we don't know where and when.
                # Probably a rare situation, usually if a problem is
                # reported we display a list of reports here.
                self.lbl_reported_value.set_text(_('yes'))
        else:
            # Translators: Displayed after 'Reported' if a problem
            # has not been reported.
            self.lbl_reported_value.set_text(_('no'))
コード例 #47
0
ファイル: views.py プロジェクト: clockfort/gnome-abrt
    def __init__(self, application, source, controller):
        Gtk.ApplicationWindow.__init__(self,
                            title=_('Automatic Bug Reporting Tool'),
                            application=application)

        self._builder = OopsWindow.OopsGtkBuilder()
        self.set_default_size(*self._builder.wnd_main.get_size())
        self._builder.wnd_main.remove(self._builder.gr_main_layout)
        #pylint: disable=E1101
        self.add(self._builder.gr_main_layout)

        # move accelators group from the design window to this window
        self.add_accel_group(self._builder.ag_accelerators)

        css_prv = Gtk.CssProvider()
        css_prv.load_from_data("GtkViewport {\n"
                               "  background-color : @theme_bg_color;\n"
                               "}\n")
        stl_ctx = self.get_style_context()
        stl_ctx.add_provider_for_screen(stl_ctx.get_screen(), css_prv, 6000)
        self._builder.connect_signals(self)

        self.selected_problem = None
        self._source = source
        self._reloading = False
        self._controller = controller

        self._builder.ls_problems.set_sort_column_id(0, Gtk.SortType.DESCENDING)
        self._builder.ls_problems.set_sort_func(0, time_sort_func, None)
        self._filter = ProblemsFilter(self, self._builder.tv_problems)

        class SourceObserver:
            def __init__(self, wnd):
                self.wnd = wnd

            def changed(self, source, change_type=None, problem=None):
                if not change_type:
                    self.wnd._reload_problems(source)
                elif change_type == problems.ProblemSource.NEW_PROBLEM:
                    self.wnd._add_problem_to_storage(problem)
                elif change_type == problems.ProblemSource.DELETED_PROBLEM:
                    self.wnd._remove_problem_from_storage(problem)
                elif change_type == problems.ProblemSource.CHANGED_PROBLEM:
                    self.wnd._update_problem_in_storage(problem)


        self._source_observer = SourceObserver(self)
        self._source.attach(self._source_observer)

        self._builder.tv_problems.grab_focus()
        self._reload_problems(self._source)

        class OptionsObserver:
            def __init__(self, wnd):
                self.wnd = wnd

            def option_updated(self, conf, option):
                if option == 'problemid' and conf[option]:
                    self.wnd._select_problem_by_id(conf[option])

        self._options_observer = OptionsObserver(self)
        conf = config.get_configuration()
        conf.set_watch('problemid', self._options_observer)
        self._options_observer.option_updated(conf, 'problemid')
コード例 #48
0
    def _set_problem(self, problem):
        def destroy_links(widget, _):
            if widget != self.lbl_reported_value:
                widget.destroy()

        self.selected_problem = problem

        sensitive_btn = problem is not None
        self.btn_delete.set_sensitive(sensitive_btn)
        self.btn_report.set_sensitive(sensitive_btn
                                      and not problem['not-reportable'])
        self.vbx_links.foreach(destroy_links, None)
        self.vbx_problem_messages.foreach(lambda w, u: w.destroy(), None)

        if problem:
            self.nb_problem_layout.set_current_page(0)
            app = problem['application']
            if problem['type'] == 'Kerneloops':
                self.lbl_reason.set_text(_("Unexpected system error"))
                self.lbl_summary.set_text(
                    _("The system has encountered a problem and recovered."))
            elif problem['type'] == 'vmcore':
                self.lbl_reason.set_text(_("Fatal system failure"))
                self.lbl_summary.set_text(
                    _("The system has encountered a problem and could not continue."
                      ))
            else:
                if not app.name:
                    self.lbl_reason.set_text(
                        # Translators: If Application's name is unknown,
                        # display neutral header
                        # "'Type' problem has been detected". Examples:
                        #  Kerneloops problem has been detected
                        #  C/C++ problem has been detected
                        #  Python problem has been detected
                        #  Ruby problem has been detected
                        #  VMCore problem has been detected
                        #  AVC problem has been detected
                        #  Java problem has been detected
                        _("{0} problem has been detected").format(
                            problem['human_type']))
                else:
                    self.lbl_reason.set_text(
                        _("{0} quit unexpectedly").format(app.name))

                self.lbl_summary.set_text(
                    _("The application encountered a problem and could not continue."
                      ))

            self.lbl_app_name_value.set_text(
                # Translators: package name not available
                problem['package_name'] or _("N/A"))
            self.lbl_app_version_value.set_text(
                # Translators: package version not available
                problem['package_version'] or _("N/A"))
            self.lbl_detected_value.set_text(
                humanize.naturaltime(datetime.datetime.now() -
                                     problem['date']))
            self.lbl_detected_value.set_tooltip_text(problem['date'].strftime(
                config.get_configuration()['D_T_FMT']))

            icon_buf = None
            scale = self.img_app_icon.get_scale_factor()
            if app.icon:
                icon_buf = load_icon(gicon=app.icon, scale=scale)

            if icon_buf is None:
                icon_buf = load_icon(name="system-run-symbolic", scale=scale)
                self.img_app_icon.get_style_context().add_class('dim-label')
            else:
                self.img_app_icon.get_style_context().remove_class('dim-label')

            # icon_buf can be None and if it is None, no icon will be displayed
            set_icon_from_pixbuf_with_scale(self.img_app_icon, icon_buf, scale)

            self.lbl_reported_value.show()
            self.lbl_reported.set_text(_("Reported"))
            if problem['not-reportable']:
                self.lbl_reported_value.set_text(_('cannot be reported'))
                self._show_problem_links(problem['submission'])
                self._show_problem_message(problem['not-reportable'])
            elif problem['is_reported']:
                if self._show_problem_links(problem['submission']):
                    self.lbl_reported.set_text(_("Reports"))
                    self.lbl_reported_value.hide()

                    if (not any((s.name == "Bugzilla"
                                 for s in problem['submission']))):
                        self._show_problem_message(
                            _("This problem has been reported, but a <i>Bugzilla</i> ticket has not"
                              " been opened. Our developers may need more information to fix the problem.\n"
                              "Please consider also <b>reporting it</b> to Bugzilla in"
                              " order to provide that. Thank you."))
                else:
                    # Translators: Displayed after 'Reported' if a problem
                    # has been reported but we don't know where and when.
                    # Probably a rare situation, usually if a problem is
                    # reported we display a list of reports here.
                    self.lbl_reported_value.set_text(_('yes'))
            else:
                # Translators: Displayed after 'Reported' if a problem
                # has not been reported.
                self.lbl_reported_value.set_text(_('no'))
        else:
            if self._source is not None:
                self.nb_problem_layout.set_current_page(1)
            else:
                self.nb_problem_layout.set_current_page(2)
コード例 #49
0
ファイル: views.py プロジェクト: jfilak/gnome-abrt
        def __init__(self):
            builder = None
            # try to load the glade from git at first step
            ui_files = ['./src/gnome_abrt/oops.glade',
                        GNOME_ABRT_UI_DIR + '/oops.glade']
            for glade_file in ui_files:
                if os.path.exists(glade_file):
                    builder = Gtk.Builder()
                    builder.set_translation_domain(GETTEXT_PROGNAME)
                    try:
                        builder.add_from_file(filename=glade_file)
                    #pylint: disable=E0712
                    except GObject.GError as ex:
                        builder = None
                        logging.debug("Failed to load UI file: '{0}': {1}"
                                .format(glade_file, str(ex)))
                    else:
                        break
                else:
                    logging.debug("UI file does not exist: '{0}'"
                            .format(glade_file))

            if builder is None:
                raise RuntimeError(_("Failed to load UI definition"))

            self._builder = builder

            self.wnd_main = builder.get_object('wnd_main')
            self.box_window = builder.get_object('box_window')
            self.box_header_left = builder.get_object('box_header_left')
            self.box_sources_switcher = builder.get_object(
                    'box_sources_switcher')
            self.box_panel_left = builder.get_object('box_panel_left')
            self.lbl_reason = builder.get_object('lbl_reason')
            self.lbl_summary = builder.get_object('lbl_summary')
            self.lbl_app_name_value = builder.get_object('lbl_app_name_value')
            self.lbl_app_version_value = builder.get_object(
                    'lbl_app_version_value')
            self.lbl_detected_value = builder.get_object('lbl_detected_value')
            self.lbl_reported = builder.get_object('lbl_reported')
            self.lbl_reported_value = builder.get_object('lbl_reported_value')
            self.lbl_repots = builder.get_object('lbl_reports')
            self.lb_problems = builder.get_object('lb_problems')
            self.img_app_icon = builder.get_object('img_app_icon')
            self.nb_problem_layout = builder.get_object('nb_problem_layout')
            self.btn_delete = builder.get_object('btn_delete')
            self.btn_report = builder.get_object('btn_report')
            self.btn_detail = builder.get_object('btn_detail')
            self.se_problems = builder.get_object('se_problems')
            self.search_bar = builder.get_object('search_bar')
            self.chb_all_problems = builder.get_object('chb_all_problems')
            self.vbx_links = builder.get_object('vbx_links')
            self.vbx_problem_messages = builder.get_object(
                    'vbx_problem_messages')
            self.gac_report = builder.get_object('gac_report')
            self.gac_delete = builder.get_object('gac_delete')
            self.gac_open_directory = builder.get_object('gac_open_directory')
            self.gac_copy_id = builder.get_object('gac_copy_id')
            self.gac_search = builder.get_object('gac_search')
            self.tbtn_search = builder.get_object('tbtn_search')
            self.tbtn_multi_select = builder.get_object('tbtn_multi_select')

            GObject.Binding.bind_property(
                    self.tbtn_search, "active",
                    self.search_bar, "search-mode-enabled",
                    GObject.BindingFlags.BIDIRECTIONAL)

            label = Gtk.Label.new('')
            label.show()
            self.lb_problems.set_placeholder(label)
            label.connect('map', self.placeholder_mapped, self)
            label.connect('unmap', self.placeholder_unmapped, self)

            self.menu_problem_item = builder.get_object('menu_problem_item')
            self.menu_multiple_problems = builder.get_object(
                    'menu_multiple_problems')
            self.ag_accelerators = builder.get_object('ag_accelerators')
            self.header_bar = None
コード例 #50
0
ファイル: views.py プロジェクト: jfilak/gnome-abrt
class OopsWindow(Gtk.ApplicationWindow):

    _TITLE = _("Problem Reporting")

    class OopsGtkBuilder(object):
        def __init__(self):
            builder = None
            # try to load the glade from git at first step
            ui_files = ['./src/gnome_abrt/oops.glade',
                        GNOME_ABRT_UI_DIR + '/oops.glade']
            for glade_file in ui_files:
                if os.path.exists(glade_file):
                    builder = Gtk.Builder()
                    builder.set_translation_domain(GETTEXT_PROGNAME)
                    try:
                        builder.add_from_file(filename=glade_file)
                    #pylint: disable=E0712
                    except GObject.GError as ex:
                        builder = None
                        logging.debug("Failed to load UI file: '{0}': {1}"
                                .format(glade_file, str(ex)))
                    else:
                        break
                else:
                    logging.debug("UI file does not exist: '{0}'"
                            .format(glade_file))

            if builder is None:
                raise RuntimeError(_("Failed to load UI definition"))

            self._builder = builder

            self.wnd_main = builder.get_object('wnd_main')
            self.box_window = builder.get_object('box_window')
            self.box_header_left = builder.get_object('box_header_left')
            self.box_sources_switcher = builder.get_object(
                    'box_sources_switcher')
            self.box_panel_left = builder.get_object('box_panel_left')
            self.lbl_reason = builder.get_object('lbl_reason')
            self.lbl_summary = builder.get_object('lbl_summary')
            self.lbl_app_name_value = builder.get_object('lbl_app_name_value')
            self.lbl_app_version_value = builder.get_object(
                    'lbl_app_version_value')
            self.lbl_detected_value = builder.get_object('lbl_detected_value')
            self.lbl_reported = builder.get_object('lbl_reported')
            self.lbl_reported_value = builder.get_object('lbl_reported_value')
            self.lbl_repots = builder.get_object('lbl_reports')
            self.lb_problems = builder.get_object('lb_problems')
            self.img_app_icon = builder.get_object('img_app_icon')
            self.nb_problem_layout = builder.get_object('nb_problem_layout')
            self.btn_delete = builder.get_object('btn_delete')
            self.btn_report = builder.get_object('btn_report')
            self.btn_detail = builder.get_object('btn_detail')
            self.se_problems = builder.get_object('se_problems')
            self.search_bar = builder.get_object('search_bar')
            self.chb_all_problems = builder.get_object('chb_all_problems')
            self.vbx_links = builder.get_object('vbx_links')
            self.vbx_problem_messages = builder.get_object(
                    'vbx_problem_messages')
            self.gac_report = builder.get_object('gac_report')
            self.gac_delete = builder.get_object('gac_delete')
            self.gac_open_directory = builder.get_object('gac_open_directory')
            self.gac_copy_id = builder.get_object('gac_copy_id')
            self.gac_search = builder.get_object('gac_search')
            self.tbtn_search = builder.get_object('tbtn_search')
            self.tbtn_multi_select = builder.get_object('tbtn_multi_select')

            GObject.Binding.bind_property(
                    self.tbtn_search, "active",
                    self.search_bar, "search-mode-enabled",
                    GObject.BindingFlags.BIDIRECTIONAL)

            label = Gtk.Label.new('')
            label.show()
            self.lb_problems.set_placeholder(label)
            label.connect('map', self.placeholder_mapped, self)
            label.connect('unmap', self.placeholder_unmapped, self)

            self.menu_problem_item = builder.get_object('menu_problem_item')
            self.menu_multiple_problems = builder.get_object(
                    'menu_multiple_problems')
            self.ag_accelerators = builder.get_object('ag_accelerators')
            self.header_bar = None

        def placeholder_mapped(self, label, data):
            self.tbtn_multi_select.set_sensitive(False)

        def placeholder_unmapped(self, label, data):
            self.tbtn_multi_select.set_sensitive(True)

        def connect_signals(self, implementor):
            self._builder.connect_signals(implementor)

            self.search_bar.connect_entry(self.se_problems)

        def reset_window(self, window, title):
            window.set_default_size(*self.wnd_main.get_size())
            self.wnd_main.remove(self.box_window)
            #pylint: disable=E1101
            window.add(self.box_window)

            if desktop.replace_window_header():
                self.box_header.foreach(lambda w, c: c.remove(w),
                        self.box_header)

                self.header_bar = Gtk.HeaderBar.new()
                self.header_bar.pack_start(self.box_header_left)
                self.header_bar.pack_end(self.btn_report)
                self.header_bar.pack_end(self.btn_delete)

                window.set_titlebar(self.header_bar)
                self.header_bar.set_show_close_button(True)
                # window.get_title() returns None
                self.header_bar.set_title(title)

            # move accelators group from the design window to this window
            window.add_accel_group(self.ag_accelerators)

        def __getattr__(self, name):
            obj = self._builder.get_object(name)

            if obj is None:
                raise AttributeError("Builder has not member '{0}'"
                        .format(name))

            return obj


    class SourceObserver(object):
        def __init__(self, wnd):
            self.wnd = wnd
            self._enabled = True

        def enable(self):
            self._enabled = True

        def disable(self):
            self._enabled = False

        def changed(self, source, change_type=None, problem=None):
            if not self._enabled:
                return

            try:
                if source == self.wnd._source:
                    if change_type is None:
                        self.wnd._reload_problems(source)
                    elif change_type == problems.ProblemSource.NEW_PROBLEM:
                        self.wnd._add_problem_to_storage(problem)
                    elif change_type == problems.ProblemSource.DELETED_PROBLEM:
                        self.wnd._remove_problem_from_storage(problem)
                    elif change_type == problems.ProblemSource.CHANGED_PROBLEM:
                        self.wnd._update_problem_in_storage(problem)

                self.wnd._update_source_button(source)
            except errors.UnavailableSource as ex:
                self.wnd._disable_source(ex.source, ex.temporary)


    class OptionsObserver(object):
        def __init__(self, wnd):
            self.wnd = wnd

        def option_updated(self, conf, option):
            if option == 'problemid' and conf[option]:
                self.wnd._select_problem_by_id(conf[option])
            if option == 'T_FMT' and conf[option]:
                self.wnd._reload_problems(self.wnd._source)
            if option == 'D_T_FMT' and conf[option]:
                self.wnd._set_problem(self.wnd.selected_problem)


    def __init__(self, application, sources, controller):
        Gtk.ApplicationWindow.__init__(self,
                            title=OopsWindow._TITLE,
                            application=application)

        if not sources:
            raise ValueError("The source list cannot be empty!")

        self._builder = OopsWindow.OopsGtkBuilder()
        self._builder.reset_window(self, OopsWindow._TITLE)

        #pylint: disable=E1120
        css_prv = Gtk.CssProvider.new()
        css_prv.load_from_data("GtkListBoxRow {\n"
                               "  padding          : 12px;\n"
                               "}\n"
                               ".app-name-label {\n"
                               "  font-weight      : bold;\n"
                               "}\n"
                               ".oops-reason {\n"
                               "  font-size        : 120%;\n"
                               "  font-weight      : bold;\n"
                               "}\n".encode()
                               )
        stl_ctx = self.get_style_context()
        stl_ctx.add_provider_for_screen(stl_ctx.get_screen(), css_prv, 6000)
        self._builder.connect_signals(self)

        self._source_observer = OopsWindow.SourceObserver(self)
        self._source_observer.disable()

        self._reloading = False
        self._controller = controller

        self.selected_problem = None
        self._all_sources = []
        self._source = None
        self._handling_source_click = False
        self._configure_sources(sources)
        self._set_button_toggled(self._source.button, True)

        # a set where invalid problems found while sorting of the problem list
        # are stored
        self._trash = set()
        self._builder.lb_problems.set_sort_func(time_sort_func, self._trash)
        self.lss_problems = ListBoxSelection(self._builder.lb_problems,
                self.on_tvs_problems_changed)
        self._filter = ProblemsFilter(self._builder.lb_problems,
                self.lss_problems)

        self._builder.lb_problems.grab_focus()
        try:
            self._reload_problems(self._source)
        except errors.UnavailableSource as ex:
            self._disable_source(ex.source, ex.temporary)

        self._options_observer = OopsWindow.OptionsObserver(self)
        conf = config.get_configuration()
        conf.set_watch('problemid', self._options_observer)
        conf.set_watch('T_FMT', self._options_observer)
        conf.set_watch('D_T_FMT', self._options_observer)
        self._options_observer.option_updated(conf, 'problemid')
        self._builder.mi_detail.set_visible(conf['expert'])

        # enable observer
        self._source_observer.enable()

        self.connect("key-press-event", self._on_key_press_event)


    def _configure_sources(self, sources):
        for name, src in sources:
            self._all_sources.append(src)
            src.attach(self._source_observer)

            label = None
            try:
                label = format_button_source_name(name, src)
            except errors.UnavailableSource:
                logging.debug("Unavailable source: {0}".format(name))
                continue

            src_btn = Gtk.ToggleButton.new_with_label(label)
            src_btn.set_visible(True)
            # add an extra member source (I don't like it but it so easy)
            src_btn.source = src
            self._builder.box_sources_switcher.pack_start(
                    src_btn, False, True, 0)

            # add an extra member name (I don't like it but it so easy)
            src.name = name
            # add an extra member button (I don't like it but it so easy)
            src.button = src_btn
            src_btn.connect("clicked", self._on_source_btn_clicked, src)

        self._source = self._all_sources[0]

    def _update_source_button(self, source):
        name = format_button_source_name(source.name, source)
        source.button.set_label(name)

    def _set_button_toggled(self, button, state):
        # set_active() triggers the clicked signal
        # and if we set the active in program,
        # we don't want do any action in the clicked handler
        self._handling_source_click = True
        try:
            button.set_active(state)
        finally:
            self._handling_source_click = False

    def _on_source_btn_clicked(self, btn, args):
        # If True, then button's state was not changed by click
        # and we don't want to switch source
        if self._handling_source_click:
            return

        res, old_source = self._switch_source(btn.source)
        if not res:
            # switching sources failed and we have to untoggle clicked
            # source's button
            self._set_button_toggled(btn, False)
        else:
            if old_source is not None:
                # sources were switched and we have to untoggle old source's
                # button
                self._set_button_toggled(old_source.button, False)
            elif not btn.get_active():
                # source wasn't changed and we have to set toggled back if
                # someone clicked already selected button
                self._set_button_toggled(btn, True)

    def _switch_source(self, source):
        """Sets the passed source as the selected source."""

        result = True
        old_source = None
        if source != self._source:
            try:
                self._reload_problems(source)
                old_source = self._source
                self._source = source
            except errors.UnavailableSource as ex:
                self._disable_source(source, ex.temporary)
                result = False

        return (result, old_source)

    def _disable_source(self, source, temporary):
        if self._source is None or not self._all_sources:
            return

        # Some sources can be components of other sources.
        # Problems are connected directly to the component sources, therefore
        # exception's source is a component source, thus we have to find an
        # instance of composite source which the unavailable component source
        # belongs.
        source_index = self._all_sources.index(source)

        if source_index != -1:
            real_source = self._all_sources[source_index]
            self._set_button_toggled(real_source.button, False)
            if not temporary:
                logging.debug("Disabling source")
                real_source.button.set_sensitive(False)
                self._all_sources.pop(source_index)

        if source != self._source:
            return

        # We just disabled the currently selected source. So, we should select
        # some other source. The simplest way is to select the first source
        # but only if it is not the disabled source.
        # If the disabled source is completely unavailable (not temporary) we
        # can always select the source at index 0 because the disabled
        # source was removed from the _all_sources list.
        if (not temporary or source_index != 0) and self._all_sources:
            self._source = self._all_sources[0]
            self._set_button_toggled(self._source.button, True)
        else:
            self._source = None

        try:
            self._reload_problems(self._source)
        except errors.UnavailableSource as ex:
            self._disable_source(ex.source, ex.temporary)

    @handle_problem_and_source_errors
    def _find_problem_row_full(self, problem):
        i = 0
        lb_row = self._builder.lb_problems.get_row_at_index(i)
        while lb_row is not None:
            if problem == list_box_row_to_problem(lb_row):
                break

            i += 1
            lb_row = self._builder.lb_problems.get_row_at_index(i)

        return (i, lb_row)

    @handle_problem_and_source_errors
    def _find_problem_row(self, problem):
        return self._find_problem_row_full(problem)[1]

    def _add_problem_to_storage(self, problem):
        try:
            values = problem_to_storage_values(problem)
        except errors.InvalidProblem:
            logging.debug("Exception: {0}".format(traceback.format_exc()))
            return

        self._append_problem_values_to_storage(values)

    def _append_problem_values_to_storage(self, problem_values):
        problem_cell = ProblemListBoxCell(problem_values)
        self._builder.lb_problems.insert(problem_cell, -1)
        self._clear_invalid_problems_trash()

    def _clear_invalid_problems_trash(self):
        # append methods trigger time_sort_func() where InvalidProblem
        # exception can occur. In that case time_sort_func() pushes an invalid
        # problem to the trash set because the invalid problem cannot be
        # removed while executing the operation
        while self._trash:
            self._remove_problem_from_storage(self._trash.pop())

    def _remove_problem_from_storage(self, problem):
        if problem is None:
            return

        index, problem_row = self._find_problem_row_full(problem)
        if problem_row is None:
            return

        selected = problem in self._get_selected(self.lss_problems)

        problem_row.destroy()

        if selected:
            for i in range(index, -1, -1):
                problem_row = self._builder.lb_problems.get_row_at_index(i)
                if self._filter.match(problem_row):
                    break

            if problem_row is not None:
                self._builder.lb_problems.select_row(problem_row)
            else:
                self._set_problem(None)

    def _update_problem_in_storage(self, problem):
        problem_row = self._find_problem_row(problem)
        if problem_row is not None:
            try:
                values = problem_to_storage_values(problem)
            except errors.InvalidProblem as ex:
                logging.debug("Exception: {0}".format(traceback.format_exc()))
                self._remove_problem_from_storage(ex.problem_id)
                return

            list_box_row_set_values(problem_row, values)
            self._builder.lb_problems.invalidate_sort()
            self._clear_invalid_problems_trash()

        if problem in self._get_selected(self.lss_problems):
            self._set_problem(problem)

    def _reload_problems(self, source):
        # Try to load and prepare the list of selected problems before we
        # clear the view. So, we can gracefully handle UnavailableSource
        # exception. If the reloaded source is unavailable the old list
        # of problems remains untouched.
        storage_problems = []
        if source is not None:
            prblms = source.get_problems()
            for p in prblms:
                try:
                    storage_problems.append(problem_to_storage_values(p))
                except errors.InvalidProblem:
                    logging.debug("Exception: {0}"
                            .format(traceback.format_exc()))

        old_selection = self._get_selected(self.lss_problems)

        self._reloading = True
        try:
            self._builder.lb_problems.foreach(
                lambda w, u: w.destroy(), None)

            if storage_problems:
                for p in storage_problems:
                    self._append_problem_values_to_storage(p)
        finally:
            self._reloading = False

        if storage_problems:
            problem_row = None
            if old_selection:
                problem_row = self._find_problem_row(old_selection[0])

            i = 0
            if problem_row is None:
                problem_row = self._builder.lb_problems.get_row_at_index(i)
                i = 1

            while (problem_row is not None
                    and not self._filter.match(problem_row)):
                problem_row = self._builder.lb_problems.get_row_at_index(i)
                i += 1

            if problem_row is not None:
                self._builder.lb_problems.select_row(problem_row)
                return

        self._set_problem(None)

    def _select_problem_by_id(self, problem_id):
        # The problem could come from a different source than the currently
        # loaded source. If so, try to switch to problem's origin source and
        # select the problem after that.
        if (self._source is not None and
                problem_id not in self._source.get_problems()):
            for source in self._all_sources:
                if problem_id in source.get_problems():
                    res, old_source = self._switch_source(source)
                    if res:
                        self._set_button_toggled(old_source.button, False)
                        self._set_button_toggled(source.button, True)
                    break

        problem_row = self._find_problem_row(problem_id)

        if problem_row is not None:
            self._builder.lb_problems.select_row(problem_row)
        else:
            logging.debug("Can't select problem id '{0}' because the id was "
                    "not found".format(problem_id))

    def _show_problem_links(self, submissions):
        if not submissions:
            return False

        link_added = False
        for sbm in submissions:
            if problems.Problem.Submission.URL == sbm.rtype:
                lnk = Gtk.Label.new(sbm.title)
                lnk.set_use_markup(True)
                lnk.set_markup(
                    "<a href=\"{0}\">{1}</a>".format(sbm.data, sbm.title))
                lnk.set_halign(Gtk.Align.START)
                lnk.set_margin_top(5)
                lnk.set_margin_bottom(8)
                lnk.set_line_wrap(True)
                lnk.set_visible(True)

                self._builder.vbx_links.pack_start(lnk, False, True, 0)
                link_added = True

        return link_added

    def _show_problem_message(self, message):
        msg = Gtk.Label.new(message)
        msg.set_markup(message)
        msg.set_visible(True)
        msg.set_halign(Gtk.Align.START)
        msg.set_valign(Gtk.Align.START)
        msg.set_line_wrap(True)
        msg.set_selectable(True)
        msg.set_xalign(0)

        self._builder.vbx_problem_messages.pack_start(msg, False, True, 0)

    @handle_problem_and_source_errors
    def _set_problem(self, problem):
        def destroy_links(widget, _):
            if widget != self._builder.lbl_reported_value:
                widget.destroy()

        self.selected_problem = problem

        sensitive_btn = problem is not None
        self._builder.btn_delete.set_sensitive(sensitive_btn)
        self._builder.btn_report.set_sensitive(
                sensitive_btn and not problem['not-reportable'])
        self._builder.vbx_links.foreach(
                destroy_links, None)
        self._builder.vbx_problem_messages.foreach(
                lambda w, u: w.destroy(), None)

        if problem:
            self._builder.nb_problem_layout.set_current_page(0)
            app = problem['application']
            if problem['type'] == 'Kerneloops':
                self._builder.lbl_reason.set_text(
            _("Unexpected system error"))
                self._builder.lbl_summary.set_text(
            _("The system has encountered a problem and recovered."))
            elif problem['type'] == 'vmcore':
                self._builder.lbl_reason.set_text(
            _("Fatal system failure"))
                self._builder.lbl_summary.set_text(
            _("The system has encountered a problem and could not continue."))
            else:
                if not app.name:
                    self._builder.lbl_reason.set_text(
                            # Translators: If Application's name is unknown,
                            # display neutral header
                            # "'Type' problem has been detected". Examples:
                            #  Kerneloops problem has been detected
                            #  C/C++ problem has been detected
                            #  Python problem has been detected
                            #  Ruby problem has been detected
                            #  VMCore problem has been detected
                            #  AVC problem has been detected
                            #  Java problem has been detected
                            _("{0} problem has been detected").format(
                                    problem['human_type']))
                else:
                    self._builder.lbl_reason.set_text(
                            _("{0} quit unexpectedly").format(app.name))

                self._builder.lbl_summary.set_text(
            _("The application encountered a problem and could not continue."))

            self._builder.lbl_app_name_value.set_text(
                        # Translators: package name not available
                        problem['package_name'] or _("N/A"))
            self._builder.lbl_app_version_value.set_text(
                        # Translators: package version not available
                        problem['package_version'] or _("N/A"))
            self._builder.lbl_detected_value.set_text(
                humanize.naturaltime(datetime.datetime.now()-problem['date']))
            self._builder.lbl_detected_value.set_tooltip_text(
                problem['date'].strftime(config.get_configuration()['D_T_FMT']))

            icon_buf = None
            scale = self._builder.img_app_icon.get_scale_factor()
            if app.icon:
                icon_buf = load_icon(gicon=app.icon, scale=scale)

            if icon_buf is None:
                icon_buf = load_icon(name="system-run-symbolic", scale=scale)
                self._builder.img_app_icon.get_style_context().add_class(
                                                                    'dim-label')
            else:
                self._builder.img_app_icon.get_style_context().remove_class(
                                                                    'dim-label')

            # icon_buf can be None and if it is None, no icon will be displayed
            set_icon_from_pixbuf_with_scale(self._builder.img_app_icon,
                                            icon_buf, scale)

            self._builder.lbl_reported_value.show()
            self._builder.lbl_reported.set_text(_("Reported"))
            if problem['not-reportable']:
                self._builder.lbl_reported_value.set_text(
                        _('cannot be reported'))
                self._show_problem_links(problem['submission'])
                self._show_problem_message(problem['not-reportable'])
            elif problem['is_reported']:
                if self._show_problem_links(problem['submission']):
                    self._builder.lbl_reported.set_text(_("Reports"))
                    self._builder.lbl_reported_value.hide()

                    if (not any((s.name == "Bugzilla"
                                for s in problem['submission']))):
                        self._show_problem_message(
_("This problem has been reported, but a <i>Bugzilla</i> ticket has not"
" been opened. Our developers may need more information to fix the problem.\n"
"Please consider also <b>reporting it</b> to Bugzilla in"
" order to provide that. Thank you."))
                else:
                    # Translators: Displayed after 'Reported' if a problem
                    # has been reported but we don't know where and when.
                    # Probably a rare situation, usually if a problem is
                    # reported we display a list of reports here.
                    self._builder.lbl_reported_value.set_text(_('yes'))
            else:
                # Translators: Displayed after 'Reported' if a problem
                # has not been reported.
                self._builder.lbl_reported_value.set_text(_('no'))
        else:
            if self._source is not None:
                self._builder.nb_problem_layout.set_current_page(1)
            else:
                self._builder.nb_problem_layout.set_current_page(2)

    def _get_selected(self, selection):
        return selection.get_selected_rows()

    def on_tbtn_multi_select_toggled(self, tbtn):
        if tbtn.get_active():
            self._builder.lb_problems.set_selection_mode(
                    Gtk.SelectionMode.MULTIPLE)
            if self._builder.header_bar is not None:
                self._builder.header_bar.get_style_context().add_class(
                                                               'selection-mode')
        else:
            row = self._builder.lb_problems.get_selected_row()
            if row is None:
                row = self._builder.lb_problems.get_row_at_index(0)

            self._builder.lb_problems.set_selection_mode(
                    Gtk.SelectionMode.BROWSE)

            if row is not None and self._filter.match(row):
                self._builder.lb_problems.select_row(row)

            if self._builder.header_bar is not None:
                self._builder.header_bar.get_style_context().remove_class(
                                                               'selection-mode')

    def on_tvs_problems_changed(self, selection):
        if not self._reloading:
            rows = self._get_selected(selection)
            if rows:
                self._set_problem(rows[0])
            else:
                # Clear window because of empty list of problems!
                self._set_problem(None)

    @handle_problem_and_source_errors
    def on_gac_delete_activate(self, action):
        for prblm in self._get_selected(self.lss_problems):
            try:
                self._controller.delete(prblm)
            except errors.InvalidProblem as ex:
                logging.debug(traceback.format_exc())
                self._remove_problem_from_storage(ex.problem_id)

    @handle_problem_and_source_errors
    def on_gac_detail_activate(self, action):
        selected = self._get_selected(self.lss_problems)
        if selected:
            wrappers.show_problem_details_for_dir(
                    selected[0].problem_id, self)

    @handle_problem_and_source_errors
    def on_gac_analyze_activate(self, action):
        selected = self._get_selected(self.lss_problems)
        if selected:
            self._controller.analyze(selected[0])

    @handle_problem_and_source_errors
    def on_gac_report_activate(self, action):
        selected = self._get_selected(self.lss_problems)
        if selected and not selected[0]['not-reportable']:
            self._controller.report(selected[0])

    @handle_problem_and_source_errors
    def on_se_problems_search_changed(self, entry):
        self._filter.set_pattern(entry.get_text())

    def _on_key_press_event(self, sender, event):
        return self._builder.search_bar.handle_event(event)

    def _hide_problem_filter(self):
        self._builder.se_problems.set_text("")
        self._builder.search_bar.set_search_mode(False)

    def _show_problem_filter(self):
        self._builder.search_bar.set_search_mode(True)
        self._builder.se_problems.grab_focus()

    def on_se_problems_key_press_event(self, sender, data):
        if data.keyval == Gdk.KEY_Escape:
            self._hide_problem_filter()

        return False

    def on_gac_search_activate(self, action):
        if self._builder.search_bar.get_search_mode():
            self._hide_problem_filter()
        else:
            self._show_problem_filter()

    def on_gac_opt_all_problems_activate(self, action):
        conf = config.get_configuration()
        conf['all_problems'] = self._builder.chb_all_problems.get_active()

    def on_gac_control_preferences_activate(self, action):
        wrappers.show_events_list_dialog(self)

    def on_gac_open_directory_activate(self, action):
        selection = self._get_selected(self.lss_problems)
        if selection:
            Gio.app_info_launch_default_for_uri(
                                'file://' + selection[0].problem_id, None)
        self._builder.menu_problem_item.popdown()
        self._builder.menu_multiple_problems.popdown()

    def on_gac_copy_id_activate(self, action):
        selection = self._get_selected(self.lss_problems)
        if selection:
            #pylint: disable=E1101
            (Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
                .set_text(selection[0].problem_id, -1))
        self._builder.menu_problem_item.popdown()
        self._builder.menu_multiple_problems.popdown()

    def problems_button_press_event(self, sender, data):
        # getattribute() used because number as first character in name
        # is syntax error
        if (data.type == type.__getattribute__(Gdk.EventType, '2BUTTON_PRESS')
                and data.button == Gdk.BUTTON_PRIMARY):
            self._builder.gac_report.activate()
        elif (data.type == Gdk.EventType.BUTTON_PRESS
                and data.button == Gdk.BUTTON_SECONDARY):
            if len(self.lss_problems.get_selected_rows()) > 1:
                self._builder.menu_multiple_problems.popup(None, None,
                        None, None, data.button, data.time)
                return True
            else:
                problem_row = self._builder.lb_problems.get_row_at_y(data.y)
                if problem_row:
                    self._builder.lb_problems.select_row(problem_row)
                    self._builder.menu_problem_item.popup(None, None,
                            None, None, data.button, data.time)

    def get_box_header_left_offset(self):
        # Returns the offset of box_header_left relative to the main paned
        # widget: distance between the left edges of the widgets in LTR
        # locales or the right edges in RTL locales.
        box_header_left = self._builder.box_header_left
        box_panel_left = self._builder.box_panel_left
        paned = box_panel_left.get_parent()
        offset = box_header_left.translate_coordinates(paned, 0, 0)[0]
        parent = box_header_left.get_parent()
        if parent is not None:
            if parent.get_direction() == Gtk.TextDirection.RTL:
                offset = paned.get_allocation().width - offset - \
                         box_header_left.get_allocation().width

        return offset

    def do_box_header_left_size_allocate(self, sender):
        # When something changes in the left group of header widgets
        # (for example the number of "My" or "System" bugs is changed
        # and requires more or less space) get its new minimum width
        # and set it as the minimum width of the left panel.
        # Unfortunately, we can't just call sender.get_preferred_width()
        # because once we set the minimum width (set_size_request())
        # of this box that value may be returned rather than the real
        # minimum value required by the box. So here we repeat roughly
        # the same algorithm which is inside the GtkBox implementation:
        # calculate the sum of minimum widths required by the children.
        spacing = sender.get_spacing()
        sum_width = -spacing
        for child in sender.get_children():
            width = child.get_preferred_width()[0]  # child's minimum width
            sum_width += width
            sum_width += spacing

        # Calculate the position of the box relative to its parent
        padding = self.get_box_header_left_offset()

        # This assumes that the right padding is the same as the left padding
        self._builder.box_panel_left.set_size_request(
                sum_width + 2 * padding, -1)

        return GLib.SOURCE_REMOVE

    def on_box_header_left_size_allocate(self, sender, allocation):
        other = self._builder.box_panel_left

        # Sometimes this function is called too early. All widgets must
        # be realized in order to measure their relative position.
        if not sender.get_realized() or not other.get_realized():
            return

        # We can't set the new size request while a widget size is being
        # allocated because the widget must be fully measured and the new
        # size request clears the measured flag causing a warning. For the
        # same reason we can't set the new size request of another widget
        # sharing the same common toplevel because the new size requsest
        # causes resize of all its parents including the common parent which
        # is just being allocated. To avoid this we schedule this action
        # on idle.
        GLib.idle_add(self.do_box_header_left_size_allocate, sender)

    def update_box_header_left_size_from_paned(self, sender):
        # Sets the box_header_left width the same as the paned position
        # minus optional margins
        other = self._builder.box_header_left

        # Sometimes this function is called too early. All widgets must
        # be realized in order to measure their relative position.
        if not sender.get_realized() or not other.get_realized():
            return GLib.SOURCE_REMOVE

        padding = self.get_box_header_left_offset()
        self._builder.box_header_left.set_size_request(
                sender.get_position() - 2 * padding, -1)

        # Sometimes the new width request is accepted (get_size_request()
        # returns the new value correctly) but not applied (the actual widget
        # width is old and unnecessarily larger). Not sure whose bug this is
        # but to workaround let's force resize.
        self._builder.box_header_left.queue_resize()
        return GLib.SOURCE_REMOVE

    def on_paned_position_changed(self, sender, data):
        # Alternatively we could watch box_panel_left size-allocate signal
        # but that other method seemed to be delayed and not updated the
        # size correctly.
        self.update_box_header_left_size_from_paned(sender)

    def on_paned_size_allocate(self, sender, allocation):
        # Sometimes when the paned position is changed as a result of the
        # resize of whole window (for example unmaximization) the paned
        # position is not notified correctly. Again, not sure whose bug this
        # is but to workaround let's watch the size of the paned and update
        # the header box size. Same as previously, we should not resize
        # any widget even when another widget is being allocated so schedule
        # this action on idle.
        GLib.idle_add(self.update_box_header_left_size_from_paned, sender)

    def on_paned_map(self, sender):
        # Also on the first appearance force the paned position changed event
        # to update the box_header_left minimum width. Otherwise it is not
        # adjusted to the paned handle position until a user moves the handle
        # manually.
        self.on_paned_position_changed(sender, None)
コード例 #51
0
class OopsWindow(Gtk.ApplicationWindow):

    _TITLE = _("Problem Reporting")

    class OopsGtkBuilder(object):
        def __init__(self):
            builder = None
            # try to load the glade from git at first step
            ui_files = [
                './src/gnome_abrt/oops.glade',
                GNOME_ABRT_UI_DIR + '/oops.glade'
            ]
            for glade_file in ui_files:
                if os.path.exists(glade_file):
                    builder = Gtk.Builder()
                    builder.set_translation_domain(GETTEXT_PROGNAME)
                    try:
                        builder.add_from_file(filename=glade_file)
                    #pylint: disable=E0712
                    except GObject.GError as ex:
                        builder = None
                        logging.debug(
                            "Failed to load UI file: '{0}': {1}".format(
                                glade_file, str(ex)))
                    else:
                        break
                else:
                    logging.debug(
                        "UI file does not exist: '{0}'".format(glade_file))

            if builder is None:
                raise RuntimeError(_("Failed to load UI definition"))

            self._builder = builder

            self.wnd_main = builder.get_object('wnd_main')
            self.box_window = builder.get_object('box_window')
            self.box_sources_switcher = builder.get_object(
                'box_sources_switcher')
            self.lbl_reason = builder.get_object('lbl_reason')
            self.lbl_summary = builder.get_object('lbl_summary')
            self.lbl_app_name_value = builder.get_object('lbl_app_name_value')
            self.lbl_app_version_value = builder.get_object(
                'lbl_app_version_value')
            self.lbl_detected_value = builder.get_object('lbl_detected_value')
            self.lbl_reported = builder.get_object('lbl_reported')
            self.lbl_reported_value = builder.get_object('lbl_reported_value')
            self.lbl_repots = builder.get_object('lbl_reports')
            self.lb_problems = builder.get_object('lb_problems')
            self.img_app_icon = builder.get_object('img_app_icon')
            self.nb_problem_layout = builder.get_object('nb_problem_layout')
            self.btn_delete = builder.get_object('btn_delete')
            self.btn_report = builder.get_object('btn_report')
            self.btn_detail = builder.get_object('btn_detail')
            self.se_problems = builder.get_object('se_problems')
            self.search_bar = builder.get_object('search_bar')
            self.chb_all_problems = builder.get_object('chb_all_problems')
            self.vbx_links = builder.get_object('vbx_links')
            self.vbx_problem_messages = builder.get_object(
                'vbx_problem_messages')
            self.gac_report = builder.get_object('gac_report')
            self.gac_delete = builder.get_object('gac_delete')
            self.gac_open_directory = builder.get_object('gac_open_directory')
            self.gac_copy_id = builder.get_object('gac_copy_id')
            self.gac_search = builder.get_object('gac_search')
            self.menu_problem_item = builder.get_object('menu_problem_item')
            self.menu_multiple_problems = builder.get_object(
                'menu_multiple_problems')
            self.ag_accelerators = builder.get_object('ag_accelerators')
            self.header_bar = None

        def connect_signals(self, implementor):
            self._builder.connect_signals(implementor)

            self.search_bar.connect_entry(self.se_problems)

        def reset_window(self, window, title):
            window.set_default_size(*self.wnd_main.get_size())
            self.wnd_main.remove(self.box_window)
            #pylint: disable=E1101
            window.add(self.box_window)

            if desktop.replace_window_header():
                self.box_header.foreach(lambda w, c: c.remove(w),
                                        self.box_header)

                self.header_bar = Gtk.HeaderBar.new()
                self.header_bar.pack_start(self.box_sources_switcher)
                self.header_bar.pack_start(self.tbtn_multi_select)
                self.header_bar.pack_end(self.btn_detail)
                self.header_bar.pack_end(self.btn_report)
                self.header_bar.pack_end(self.btn_delete)

                window.set_titlebar(self.header_bar)
                self.header_bar.set_show_close_button(True)
                # window.get_title() returns None
                self.header_bar.set_title(title)

            # move accelators group from the design window to this window
            window.add_accel_group(self.ag_accelerators)

        def __getattr__(self, name):
            obj = self._builder.get_object(name)

            if obj is None:
                raise AttributeError(
                    "Builder has not member '{0}'".format(name))

            return obj

    class SourceObserver(object):
        def __init__(self, wnd):
            self.wnd = wnd
            self._enabled = True

        def enable(self):
            self._enabled = True

        def disable(self):
            self._enabled = False

        def changed(self, source, change_type=None, problem=None):
            if not self._enabled:
                return

            try:
                if source == self.wnd._source:
                    if change_type is None:
                        self.wnd._reload_problems(source)
                    elif change_type == problems.ProblemSource.NEW_PROBLEM:
                        self.wnd._add_problem_to_storage(problem)
                    elif change_type == problems.ProblemSource.DELETED_PROBLEM:
                        self.wnd._remove_problem_from_storage(problem)
                    elif change_type == problems.ProblemSource.CHANGED_PROBLEM:
                        self.wnd._update_problem_in_storage(problem)

                self.wnd._update_source_button(source)
            except errors.UnavailableSource as ex:
                self.wnd._disable_source(ex.source, ex.temporary)

    class OptionsObserver(object):
        def __init__(self, wnd):
            self.wnd = wnd

        def option_updated(self, conf, option):
            if option == 'problemid' and conf[option]:
                self.wnd._select_problem_by_id(conf[option])
            if option == 'T_FMT' and conf[option]:
                self.wnd._reload_problems(self.wnd._source)
            if option == 'D_T_FMT' and conf[option]:
                self.wnd._set_problem(self.wnd.selected_problem)

    def __init__(self, application, sources, controller):
        Gtk.ApplicationWindow.__init__(self,
                                       title=OopsWindow._TITLE,
                                       application=application)

        if not sources:
            raise ValueError("The source list cannot be empty!")

        self._builder = OopsWindow.OopsGtkBuilder()
        self._builder.reset_window(self, OopsWindow._TITLE)

        #pylint: disable=E1120
        css_prv = Gtk.CssProvider.new()
        css_prv.load_from_data("GtkViewport {\n"
                               "  background-color : @theme_bg_color;\n"
                               "}\n"
                               "GtkListBox {\n"
                               "  background-color : #e7e7e7;\n"
                               "}\n"
                               "GtkListBoxRow {\n"
                               "  padding          : 12px;\n"
                               "  background-color : #e7e7e7;\n"
                               "  border-width     : 0px 0px 2px 0px;\n"
                               "  border-color     : #efefef;\n"
                               "  border-style     : outset;\n"
                               "}\n"
                               "GtkListBoxRow:selected {\n"
                               "  background-color : #4a90d9;\n"
                               "}\n"
                               ".oops-reason {\n"
                               "  font-size        : 120%;\n"
                               "  font-weight      : bold;\n"
                               "}\n".encode())
        stl_ctx = self.get_style_context()
        stl_ctx.add_provider_for_screen(stl_ctx.get_screen(), css_prv, 6000)
        self._builder.connect_signals(self)

        self._source_observer = OopsWindow.SourceObserver(self)
        self._source_observer.disable()

        self._reloading = False
        self._controller = controller

        self.selected_problem = None
        self._all_sources = []
        self._source = None
        self._handling_source_click = False
        self._configure_sources(sources)
        self._set_button_toggled(self._source.button, True)

        # a set where invalid problems found while sorting of the problem list
        # are stored
        self._trash = set()
        self._builder.lb_problems.set_sort_func(time_sort_func, self._trash)
        self.lss_problems = ListBoxSelection(self._builder.lb_problems,
                                             self.on_tvs_problems_changed)
        self._filter = ProblemsFilter(self._builder.lb_problems,
                                      self.lss_problems)

        self._builder.lb_problems.grab_focus()
        try:
            self._reload_problems(self._source)
        except errors.UnavailableSource as ex:
            self._disable_source(ex.source, ex.temporary)

        self._options_observer = OopsWindow.OptionsObserver(self)
        conf = config.get_configuration()
        conf.set_watch('problemid', self._options_observer)
        conf.set_watch('T_FMT', self._options_observer)
        conf.set_watch('D_T_FMT', self._options_observer)
        self._options_observer.option_updated(conf, 'problemid')
        self._builder.btn_detail.set_visible(conf['expert'])
        self._builder.mi_detail.set_visible(conf['expert'])

        # enable observer
        self._source_observer.enable()

        self.connect("key-press-event", self._on_key_press_event)

    def _update_detail_buttons_visibility(self):
        self._builder.btn_detail.set_visible(self._source.allow_details)

    def _configure_sources(self, sources):
        for name, src, allow_details in sources:
            self._all_sources.append(src)
            src.attach(self._source_observer)

            label = None
            try:
                label = format_button_source_name(name, src)
            except errors.UnavailableSource:
                logging.debug("Unavailable source: {0}".format(name))
                continue

            src_btn = Gtk.ToggleButton.new_with_label(label)
            src_btn.set_visible(True)
            # add an extra member source (I don't like it but it so easy)
            src_btn.source = src
            self._builder.box_sources_switcher.pack_start(
                src_btn, False, True, 0)

            # add an extra member name (I don't like it but it so easy)
            src.name = name
            # add an extra member button (I don't like it but it so easy)
            src.button = src_btn
            # add an extra member allow_details (I don't like it but it so easy)
            src.allow_details = allow_details
            src_btn.connect("clicked", self._on_source_btn_clicked, src)

        self._source = self._all_sources[0]

    def _update_source_button(self, source):
        name = format_button_source_name(source.name, source)
        source.button.set_label(name)

    def _set_button_toggled(self, button, state):
        # set_active() triggers the clicked signal
        # and if we set the active in program,
        # we don't want do any action in the clicked handler
        self._handling_source_click = True
        try:
            button.set_active(state)
        finally:
            self._handling_source_click = False

    def _on_source_btn_clicked(self, btn, args):
        # If True, then button's state was not changed by click
        # and we don't want to switch source
        if self._handling_source_click:
            return

        res, old_source = self._switch_source(btn.source)
        if not res:
            # switching sources failed and we have to untoggle clicked
            # source's button
            self._set_button_toggled(btn, False)
        else:
            self._update_detail_buttons_visibility()
            if old_source is not None:
                # sources were switched and we have to untoggle old source's
                # button
                self._set_button_toggled(old_source.button, False)
            elif not btn.get_active():
                # source wasn't changed and we have to set toggled back if
                # someone clicked already selected button
                self._set_button_toggled(btn, True)

    def _switch_source(self, source):
        """Sets the passed source as the selected source."""

        result = True
        old_source = None
        if source != self._source:
            try:
                self._reload_problems(source)
                old_source = self._source
                self._source = source
            except errors.UnavailableSource as ex:
                self._disable_source(source, ex.temporary)
                result = False

        return (result, old_source)

    def _disable_source(self, source, temporary):
        if self._source is None or not self._all_sources:
            return

        # Some sources can be components of other sources.
        # Problems are connected directly to the component sources, therefore
        # exception's source is a component source, thus we have to find an
        # instance of composite source which the unavailable component source
        # belongs.
        source_index = self._all_sources.index(source)

        if source_index != -1:
            real_source = self._all_sources[source_index]
            self._set_button_toggled(real_source.button, False)
            if not temporary:
                logging.debug("Disabling source")
                real_source.button.set_sensitive(False)
                self._all_sources.pop(source_index)

        if source != self._source:
            return

        # We just disabled the currently selected source. So, we should select
        # some other source. The simplest way is to select the first source
        # but only if it is not the disabled source.
        # If the disabled source is completely unavailable (not temporary) we
        # can always select the source at index 0 because the disabled
        # source was removed from the _all_sources list.
        if (not temporary or source_index != 0) and self._all_sources:
            self._source = self._all_sources[0]
            self._set_button_toggled(self._source.button, True)
            self._update_detail_buttons_visibility()
        else:
            self._source = None

        try:
            self._reload_problems(self._source)
        except errors.UnavailableSource as ex:
            self._disable_source(ex.source, ex.temporary)

    @handle_problem_and_source_errors
    def _find_problem_row_full(self, problem):
        i = 0
        lb_row = self._builder.lb_problems.get_row_at_index(i)
        while lb_row is not None:
            if problem == list_box_row_to_problem(lb_row):
                break

            i += 1
            lb_row = self._builder.lb_problems.get_row_at_index(i)

        return (i, lb_row)

    @handle_problem_and_source_errors
    def _find_problem_row(self, problem):
        return self._find_problem_row_full(problem)[1]

    def _add_problem_to_storage(self, problem):
        try:
            values = problem_to_storage_values(problem)
        except errors.InvalidProblem:
            logging.debug("Exception: {0}".format(traceback.format_exc()))
            return

        self._append_problem_values_to_storage(values)

    def _append_problem_values_to_storage(self, problem_values):
        problem_cell = ProblemListBoxCell(problem_values)
        self._builder.lb_problems.insert(problem_cell, -1)
        self._clear_invalid_problems_trash()

    def _clear_invalid_problems_trash(self):
        # append methods trigger time_sort_func() where InvalidProblem
        # exception can occur. In that case time_sort_func() pushes an invalid
        # problem to the trash set because the invalid problem cannot be
        # removed while executing the operation
        while self._trash:
            self._remove_problem_from_storage(self._trash.pop())

    def _remove_problem_from_storage(self, problem):
        if problem is None:
            return

        index, problem_row = self._find_problem_row_full(problem)
        if problem_row is None:
            return

        selected = problem in self._get_selected(self.lss_problems)

        problem_row.destroy()

        if selected:
            for i in range(index, -1, -1):
                problem_row = self._builder.lb_problems.get_row_at_index(i)
                if self._filter.match(problem_row):
                    break

            if problem_row is not None:
                self._builder.lb_problems.select_row(problem_row)
            else:
                self._set_problem(None)

    def _update_problem_in_storage(self, problem):
        problem_row = self._find_problem_row(problem)
        if problem_row is not None:
            try:
                values = problem_to_storage_values(problem)
            except errors.InvalidProblem as ex:
                logging.debug("Exception: {0}".format(traceback.format_exc()))
                self._remove_problem_from_storage(ex.problem_id)
                return

            list_box_row_set_values(problem_row, values)
            self._builder.lb_problems.invalidate_sort()
            self._clear_invalid_problems_trash()

        if problem in self._get_selected(self.lss_problems):
            self._set_problem(problem)

    def _reload_problems(self, source):
        # Try to load and prepare the list of selected problems before we
        # clear the view. So, we can gracefully handle UnavailableSource
        # exception. If the reloaded source is unavailable the old list
        # of problems remains untouched.
        storage_problems = []
        if source is not None:
            prblms = source.get_problems()
            for p in prblms:
                try:
                    storage_problems.append(problem_to_storage_values(p))
                except errors.InvalidProblem:
                    logging.debug("Exception: {0}".format(
                        traceback.format_exc()))

        old_selection = self._get_selected(self.lss_problems)

        self._reloading = True
        try:
            self._builder.lb_problems.foreach(lambda w, u: w.destroy(), None)

            if storage_problems:
                for p in storage_problems:
                    self._append_problem_values_to_storage(p)
        finally:
            self._reloading = False

        if storage_problems:
            problem_row = None
            if old_selection:
                problem_row = self._find_problem_row(old_selection[0])

            i = 0
            if problem_row is None:
                problem_row = self._builder.lb_problems.get_row_at_index(i)
                i = 1

            while (problem_row is not None
                   and not self._filter.match(problem_row)):
                problem_row = self._builder.lb_problems.get_row_at_index(i)
                i += 1

            if problem_row is not None:
                self._builder.lb_problems.select_row(problem_row)
                return

        self._set_problem(None)

    def _select_problem_by_id(self, problem_id):
        # The problem could come from a different source than the currently
        # loaded source. If so, try to switch to problem's origin source and
        # select the problem after that.
        if (self._source is not None
                and not problem_id in self._source.get_problems()):
            for source in self._all_sources:
                if problem_id in source.get_problems():
                    res, old_source = self._switch_source(source)
                    if res:
                        self._set_button_toggled(old_source.button, False)
                        self._set_button_toggled(source.button, True)
                        self._update_detail_buttons_visibility()
                    break

        problem_row = self._find_problem_row(problem_id)

        if problem_row is not None:
            self._builder.lb_problems.select_row(problem_row)
        else:
            logging.debug("Can't select problem id '{0}' because the id was "
                          "not found".format(problem_id))

    def _show_problem_links(self, submissions):
        if not submissions:
            return False

        link_added = False
        for sbm in submissions:
            if problems.Problem.Submission.URL == sbm.rtype:
                lnk = Gtk.Label.new(sbm.title)
                lnk.set_use_markup(True)
                lnk.set_markup("<a href=\"{0}\">{1}</a>".format(
                    sbm.data, sbm.title))
                lnk.set_halign(Gtk.Align.START)
                lnk.set_margin_top(5)
                lnk.set_margin_bottom(8)
                lnk.set_line_wrap(True)
                lnk.set_visible(True)

                self._builder.vbx_links.pack_start(lnk, False, True, 0)
                link_added = True

        return link_added

    def _show_problem_message(self, message):
        msg = Gtk.Label.new(message)
        msg.set_markup(message)
        msg.set_visible(True)
        msg.set_halign(Gtk.Align.START)
        msg.set_valign(Gtk.Align.START)
        msg.set_line_wrap(True)
        msg.set_selectable(True)

        self._builder.vbx_problem_messages.pack_start(msg, False, True, 0)

    @handle_problem_and_source_errors
    def _set_problem(self, problem):
        def destroy_links(widget, _):
            if widget != self._builder.lbl_reported_value:
                widget.destroy()

        self.selected_problem = problem

        sensitive_btn = problem is not None
        self._builder.btn_delete.set_sensitive(sensitive_btn)
        self._builder.btn_report.set_sensitive(
            sensitive_btn and not problem['not-reportable'])
        self._builder.btn_detail.set_sensitive(sensitive_btn)
        self._builder.vbx_links.foreach(destroy_links, None)
        self._builder.vbx_problem_messages.foreach(lambda w, u: w.destroy(),
                                                   None)

        if problem:
            self._builder.nb_problem_layout.set_current_page(0)
            app = problem['application']
            if problem['type'] == 'Kerneloops':
                self._builder.lbl_reason.set_text(_("Unexpected system error"))
                self._builder.lbl_summary.set_text(
                    _("The system has encountered a problem and recovered."))
            elif problem['type'] == 'vmcore':
                self._builder.lbl_reason.set_text(_("Fatal system failure"))
                self._builder.lbl_summary.set_text(
                    _("The system has encountered a problem and could not continue."
                      ))
            else:
                if not app.name:
                    # If Application's name is unknown, display neutral
                    # header "'Type' problem has been detected":
                    #  Kerneloops problem has been detected
                    #  C/C++ problem has been detected
                    #  Python problem has been detected
                    #  Ruby problem has been detected
                    #  VMCore problem has been detected
                    #  AVC problem has been detected
                    #  Java problem has been detected
                    self._builder.lbl_reason.set_text(
                        _("{0} problem has been detected").format(
                            problem['human_type']))
                else:
                    self._builder.lbl_reason.set_text(
                        _("{0} quit unexpectedly".format(app.name)))

                self._builder.lbl_summary.set_text(
                    _("The application encountered a problem and could not continue."
                      ))

            self._builder.lbl_app_name_value.set_text(problem['package_name']
                                                      or _("N/A"))
            self._builder.lbl_app_version_value.set_text(
                problem['package_version'] or _("N/A"))
            self._builder.lbl_detected_value.set_text(
                humanize.naturaltime(datetime.datetime.now() -
                                     problem['date']))
            self._builder.lbl_detected_value.set_tooltip_text(
                problem['date'].strftime(
                    config.get_configuration()['D_T_FMT']))

            if app.icon:
                self._builder.img_app_icon.set_from_pixbuf(
                    Gtk.IconTheme.get_default().lookup_by_gicon(
                        app.icon, 128,
                        Gtk.IconLookupFlags.FORCE_SIZE).load_icon())
            else:
                self._builder.img_app_icon.set_from_pixbuf(
                    Gtk.IconTheme.get_default().lookup_icon(
                        "system-run-symbolic", 128,
                        Gtk.IconLookupFlags.FORCE_SIZE
                        | Gtk.IconLookupFlags.FORCE_SYMBOLIC).load_icon())

            self._builder.lbl_reported_value.show()
            self._builder.lbl_reported.set_text(_("Reported"))
            if problem['not-reportable']:
                self._builder.lbl_reported_value.set_text(
                    _('cannot be reported'))
                self._show_problem_links(problem['submission'])
                self._show_problem_message(problem['not-reportable'])
            elif problem['is_reported']:
                if self._show_problem_links(problem['submission']):
                    self._builder.lbl_reported.set_text(_("Reports"))
                    self._builder.lbl_reported_value.hide()

                    if (not any((s.name == "Bugzilla"
                                 for s in problem['submission']))):
                        self._show_problem_message(
                            _("This problem has been reported, but a <i>Bugzilla</i> ticket has not"
                              " been opened. Our developers may need more information to fix the problem.\n"
                              "Please consider also <b>reporting it</b> to Bugzilla in"
                              " order to provide that. Thank you."))
                else:
                    self._builder.lbl_reported_value.set_text(_('yes'))
            else:
                self._builder.lbl_reported_value.set_text(_('no'))
        else:
            if self._source is not None:
                self._builder.nb_problem_layout.set_current_page(1)
            else:
                self._builder.nb_problem_layout.set_current_page(2)

    def _get_selected(self, selection):
        return selection.get_selected_rows()

    def on_tbtn_multi_select_toggled(self, tbtn):
        if tbtn.get_active():
            self._builder.lb_problems.set_selection_mode(
                Gtk.SelectionMode.MULTIPLE)
        else:
            row = self._builder.lb_problems.get_selected_row()
            if row is None:
                row = self._builder.lb_problems.get_row_at_index(0)

            self._builder.lb_problems.set_selection_mode(
                Gtk.SelectionMode.BROWSE)

            if row is not None and self._filter.match(row):
                self._builder.lb_problems.select_row(row)

    def on_tvs_problems_changed(self, selection):
        if not self._reloading:
            rows = self._get_selected(selection)
            if rows:
                self._set_problem(rows[0])
            else:
                # Clear window because of empty list of problems!
                self._set_problem(None)

    @handle_problem_and_source_errors
    def on_gac_delete_activate(self, action):
        for prblm in self._get_selected(self.lss_problems):
            try:
                self._controller.delete(prblm)
            except errors.InvalidProblem as ex:
                logging.debug(traceback.format_exc())
                self._remove_problem_from_storage(ex.problem_id)

    @handle_problem_and_source_errors
    def on_gac_detail_activate(self, action):
        selected = self._get_selected(self.lss_problems)
        if selected:
            wrappers.show_problem_details_for_dir(selected[0].problem_id, self)

    @handle_problem_and_source_errors
    def on_gac_analyze_activate(self, action):
        selected = self._get_selected(self.lss_problems)
        if selected:
            self._controller.analyze(selected[0])

    @handle_problem_and_source_errors
    def on_gac_report_activate(self, action):
        selected = self._get_selected(self.lss_problems)
        if selected and not selected[0]['not-reportable']:
            self._controller.report(selected[0])

    @handle_problem_and_source_errors
    def on_se_problems_search_changed(self, entry):
        self._filter.set_pattern(entry.get_text())

    def _on_key_press_event(self, sender, event):
        return self._builder.search_bar.handle_event(event)

    def _hide_problem_filter(self):
        self._builder.se_problems.set_text("")
        self._builder.search_bar.set_search_mode(False)

    def _show_problem_filter(self):
        self._builder.search_bar.set_search_mode(True)
        self._builder.se_problems.grab_focus()

    def on_se_problems_key_press_event(self, sender, data):
        if data.keyval == Gdk.KEY_Escape:
            self._hide_problem_filter()

        return False

    def on_gac_search_activate(self, action):
        if self._builder.search_bar.get_search_mode():
            self._hide_problem_filter()
        else:
            self._show_problem_filter()

    def on_gac_opt_all_problems_activate(self, action):
        conf = config.get_configuration()
        conf['all_problems'] = self._builder.chb_all_problems.get_active()

    def on_gac_control_preferences_activate(self, action):
        wrappers.show_events_list_dialog(self)

    def on_gac_open_directory_activate(self, action):
        selection = self._get_selected(self.lss_problems)
        if selection:
            Gio.app_info_launch_default_for_uri(selection[0].problem_id, None)
        self._builder.menu_problem_item.popdown()
        self._builder.menu_multiple_problems.popdown()

    def on_gac_copy_id_activate(self, action):
        selection = self._get_selected(self.lss_problems)
        if selection:
            #pylint: disable=E1101
            (Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD).set_text(
                selection[0].problem_id, -1))
        self._builder.menu_problem_item.popdown()
        self._builder.menu_multiple_problems.popdown()

    def problems_button_press_event(self, sender, data):
        # getattribute() used because number as first character in name
        # is syntax error
        if (data.type == type.__getattribute__(Gdk.EventType, '2BUTTON_PRESS')
                and data.button == Gdk.BUTTON_PRIMARY):
            self._builder.gac_report.activate()
        elif (data.type == Gdk.EventType.BUTTON_PRESS
              and data.button == Gdk.BUTTON_SECONDARY):
            if len(self.lss_problems.get_selected_rows()) > 1:
                self._builder.menu_multiple_problems.popup(
                    None, None, None, None, data.button, data.time)
                return True
            else:
                problem_row = self._builder.lb_problems.get_row_at_y(data.y)
                if problem_row:
                    self._builder.lb_problems.select_row(problem_row)
                    self._builder.menu_problem_item.popup(
                        None, None, None, None, data.button, data.time)
コード例 #52
0
ファイル: views.py プロジェクト: jfilak/gnome-abrt
    def _set_problem(self, problem):
        def destroy_links(widget, _):
            if widget != self._builder.lbl_reported_value:
                widget.destroy()

        self.selected_problem = problem

        sensitive_btn = problem is not None
        self._builder.btn_delete.set_sensitive(sensitive_btn)
        self._builder.btn_report.set_sensitive(
                sensitive_btn and not problem['not-reportable'])
        self._builder.vbx_links.foreach(
                destroy_links, None)
        self._builder.vbx_problem_messages.foreach(
                lambda w, u: w.destroy(), None)

        if problem:
            self._builder.nb_problem_layout.set_current_page(0)
            app = problem['application']
            if problem['type'] == 'Kerneloops':
                self._builder.lbl_reason.set_text(
            _("Unexpected system error"))
                self._builder.lbl_summary.set_text(
            _("The system has encountered a problem and recovered."))
            elif problem['type'] == 'vmcore':
                self._builder.lbl_reason.set_text(
            _("Fatal system failure"))
                self._builder.lbl_summary.set_text(
            _("The system has encountered a problem and could not continue."))
            else:
                if not app.name:
                    self._builder.lbl_reason.set_text(
                            # Translators: If Application's name is unknown,
                            # display neutral header
                            # "'Type' problem has been detected". Examples:
                            #  Kerneloops problem has been detected
                            #  C/C++ problem has been detected
                            #  Python problem has been detected
                            #  Ruby problem has been detected
                            #  VMCore problem has been detected
                            #  AVC problem has been detected
                            #  Java problem has been detected
                            _("{0} problem has been detected").format(
                                    problem['human_type']))
                else:
                    self._builder.lbl_reason.set_text(
                            _("{0} quit unexpectedly").format(app.name))

                self._builder.lbl_summary.set_text(
            _("The application encountered a problem and could not continue."))

            self._builder.lbl_app_name_value.set_text(
                        # Translators: package name not available
                        problem['package_name'] or _("N/A"))
            self._builder.lbl_app_version_value.set_text(
                        # Translators: package version not available
                        problem['package_version'] or _("N/A"))
            self._builder.lbl_detected_value.set_text(
                humanize.naturaltime(datetime.datetime.now()-problem['date']))
            self._builder.lbl_detected_value.set_tooltip_text(
                problem['date'].strftime(config.get_configuration()['D_T_FMT']))

            icon_buf = None
            scale = self._builder.img_app_icon.get_scale_factor()
            if app.icon:
                icon_buf = load_icon(gicon=app.icon, scale=scale)

            if icon_buf is None:
                icon_buf = load_icon(name="system-run-symbolic", scale=scale)
                self._builder.img_app_icon.get_style_context().add_class(
                                                                    'dim-label')
            else:
                self._builder.img_app_icon.get_style_context().remove_class(
                                                                    'dim-label')

            # icon_buf can be None and if it is None, no icon will be displayed
            set_icon_from_pixbuf_with_scale(self._builder.img_app_icon,
                                            icon_buf, scale)

            self._builder.lbl_reported_value.show()
            self._builder.lbl_reported.set_text(_("Reported"))
            if problem['not-reportable']:
                self._builder.lbl_reported_value.set_text(
                        _('cannot be reported'))
                self._show_problem_links(problem['submission'])
                self._show_problem_message(problem['not-reportable'])
            elif problem['is_reported']:
                if self._show_problem_links(problem['submission']):
                    self._builder.lbl_reported.set_text(_("Reports"))
                    self._builder.lbl_reported_value.hide()

                    if (not any((s.name == "Bugzilla"
                                for s in problem['submission']))):
                        self._show_problem_message(
_("This problem has been reported, but a <i>Bugzilla</i> ticket has not"
" been opened. Our developers may need more information to fix the problem.\n"
"Please consider also <b>reporting it</b> to Bugzilla in"
" order to provide that. Thank you."))
                else:
                    # Translators: Displayed after 'Reported' if a problem
                    # has been reported but we don't know where and when.
                    # Probably a rare situation, usually if a problem is
                    # reported we display a list of reports here.
                    self._builder.lbl_reported_value.set_text(_('yes'))
            else:
                # Translators: Displayed after 'Reported' if a problem
                # has not been reported.
                self._builder.lbl_reported_value.set_text(_('no'))
        else:
            if self._source is not None:
                self._builder.nb_problem_layout.set_current_page(1)
            else:
                self._builder.nb_problem_layout.set_current_page(2)
コード例 #53
0
    def _set_problem(self, problem):
        def destroy_links(widget, _):
            if widget != self._builder.lbl_reported_value:
                widget.destroy()

        self.selected_problem = problem

        sensitive_btn = problem is not None
        self._builder.btn_delete.set_sensitive(sensitive_btn)
        self._builder.btn_report.set_sensitive(
            sensitive_btn and not problem['not-reportable'])
        self._builder.btn_detail.set_sensitive(sensitive_btn)
        self._builder.vbx_links.foreach(destroy_links, None)
        self._builder.vbx_problem_messages.foreach(lambda w, u: w.destroy(),
                                                   None)

        if problem:
            self._builder.nb_problem_layout.set_current_page(0)
            app = problem['application']
            if problem['type'] == 'Kerneloops':
                self._builder.lbl_reason.set_text(_("Unexpected system error"))
                self._builder.lbl_summary.set_text(
                    _("The system has encountered a problem and recovered."))
            elif problem['type'] == 'vmcore':
                self._builder.lbl_reason.set_text(_("Fatal system failure"))
                self._builder.lbl_summary.set_text(
                    _("The system has encountered a problem and could not continue."
                      ))
            else:
                if not app.name:
                    # If Application's name is unknown, display neutral
                    # header "'Type' problem has been detected":
                    #  Kerneloops problem has been detected
                    #  C/C++ problem has been detected
                    #  Python problem has been detected
                    #  Ruby problem has been detected
                    #  VMCore problem has been detected
                    #  AVC problem has been detected
                    #  Java problem has been detected
                    self._builder.lbl_reason.set_text(
                        _("{0} problem has been detected").format(
                            problem['human_type']))
                else:
                    self._builder.lbl_reason.set_text(
                        _("{0} quit unexpectedly".format(app.name)))

                self._builder.lbl_summary.set_text(
                    _("The application encountered a problem and could not continue."
                      ))

            self._builder.lbl_app_name_value.set_text(problem['package_name']
                                                      or _("N/A"))
            self._builder.lbl_app_version_value.set_text(
                problem['package_version'] or _("N/A"))
            self._builder.lbl_detected_value.set_text(
                humanize.naturaltime(datetime.datetime.now() -
                                     problem['date']))
            self._builder.lbl_detected_value.set_tooltip_text(
                problem['date'].strftime(
                    config.get_configuration()['D_T_FMT']))

            if app.icon:
                self._builder.img_app_icon.set_from_pixbuf(
                    Gtk.IconTheme.get_default().lookup_by_gicon(
                        app.icon, 128,
                        Gtk.IconLookupFlags.FORCE_SIZE).load_icon())
            else:
                self._builder.img_app_icon.set_from_pixbuf(
                    Gtk.IconTheme.get_default().lookup_icon(
                        "system-run-symbolic", 128,
                        Gtk.IconLookupFlags.FORCE_SIZE
                        | Gtk.IconLookupFlags.FORCE_SYMBOLIC).load_icon())

            self._builder.lbl_reported_value.show()
            self._builder.lbl_reported.set_text(_("Reported"))
            if problem['not-reportable']:
                self._builder.lbl_reported_value.set_text(
                    _('cannot be reported'))
                self._show_problem_links(problem['submission'])
                self._show_problem_message(problem['not-reportable'])
            elif problem['is_reported']:
                if self._show_problem_links(problem['submission']):
                    self._builder.lbl_reported.set_text(_("Reports"))
                    self._builder.lbl_reported_value.hide()

                    if (not any((s.name == "Bugzilla"
                                 for s in problem['submission']))):
                        self._show_problem_message(
                            _("This problem has been reported, but a <i>Bugzilla</i> ticket has not"
                              " been opened. Our developers may need more information to fix the problem.\n"
                              "Please consider also <b>reporting it</b> to Bugzilla in"
                              " order to provide that. Thank you."))
                else:
                    self._builder.lbl_reported_value.set_text(_('yes'))
            else:
                self._builder.lbl_reported_value.set_text(_('no'))
        else:
            if self._source is not None:
                self._builder.nb_problem_layout.set_current_page(1)
            else:
                self._builder.nb_problem_layout.set_current_page(2)