From 136dfd3c7ccf2d3235ec69db4eb9af00b364ba8c Mon Sep 17 00:00:00 2001 From: Jakub Filak Date: Mon, 25 Aug 2014 17:18:02 +0200 Subject: [LIBREPORT PATCH] gui: Problem Details suite + ProblemDetailsWidget + ProblemDetailsDialog Related to abrt/gnome-abrt#64 Signed-off-by: Jakub Filak --- po/POTFILES.in | 2 + src/gtk-helpers/Makefile.am | 10 +- src/gtk-helpers/internal_libreport_gtk.h | 6 + src/gtk-helpers/problem_details_dialog.c | 80 +++++++ src/gtk-helpers/problem_details_dialog.h | 37 +++ src/gtk-helpers/problem_details_widget.c | 375 +++++++++++++++++++++++++++++++ src/gtk-helpers/problem_details_widget.h | 62 +++++ src/gtk-helpers/utils.c | 25 +++ src/gui-wizard-gtk/wizard.c | 21 +- 9 files changed, 596 insertions(+), 22 deletions(-) create mode 100644 src/gtk-helpers/problem_details_dialog.c create mode 100644 src/gtk-helpers/problem_details_dialog.h create mode 100644 src/gtk-helpers/problem_details_widget.c create mode 100644 src/gtk-helpers/problem_details_widget.h create mode 100644 src/gtk-helpers/utils.c diff --git a/po/POTFILES.in b/po/POTFILES.in index 4a0b565..c599dab 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -10,6 +10,8 @@ src/gtk-helpers/config_dialog.c src/gtk-helpers/event_config_dialog.c src/gtk-helpers/secrets.c src/gtk-helpers/workflow_config_dialog.c +src/gtk-helpers/problem_details_widget.c +src/gtk-helpers/problem_details_dialog.c src/gui-wizard-gtk/main.c src/gui-wizard-gtk/wizard.c src/gui-wizard-gtk/wizard.glade diff --git a/src/gtk-helpers/Makefile.am b/src/gtk-helpers/Makefile.am index 13b9072..a7cc554 100644 --- a/src/gtk-helpers/Makefile.am +++ b/src/gtk-helpers/Makefile.am @@ -3,12 +3,15 @@ libreport_gtk_includedir = \ $(includedir)/libreport libreport_gtk_include_HEADERS = \ - internal_libreport_gtk.h + internal_libreport_gtk.h \ + problem_details_widget.h \ + problem_details_dialog.h lib_LTLIBRARIES = \ libreport-gtk.la libreport_gtk_la_SOURCES = \ + utils.c \ event_config_dialog.c \ secrets.c \ hyperlinks.c \ @@ -16,11 +19,14 @@ libreport_gtk_la_SOURCES = \ workflow_config_dialog.c \ config_dialog.c \ ask_dialogs.c \ - search_item.c search_item.h + search_item.c search_item.h \ + problem_details_widget.c problem_details_widget.h \ + problem_details_dialog.c problem_details_dialog.h libreport_gtk_la_CPPFLAGS = \ -I$(srcdir)/../include \ -I$(srcdir)/../lib \ + -Wno-error=unused-local-typedefs \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \ diff --git a/src/gtk-helpers/internal_libreport_gtk.h b/src/gtk-helpers/internal_libreport_gtk.h index f8f1c13..57f5889 100644 --- a/src/gtk-helpers/internal_libreport_gtk.h +++ b/src/gtk-helpers/internal_libreport_gtk.h @@ -20,6 +20,8 @@ #define INTERNAL_LIBREPORT_GTK_H_ #include +#include "problem_details_dialog.h" +#include "problem_details_widget.h" #include "report.h" #include "internal_libreport.h" @@ -96,6 +98,10 @@ struct url_token #define find_url_tokens libreport_find_url_tokens GList *find_url_tokens(const char *line); + +#define reload_text_to_text_view libreport_reload_text_to_text_view +void reload_text_to_text_view(GtkTextView *tv, const char *text); + /* Ask dialogs */ /* diff --git a/src/gtk-helpers/problem_details_dialog.c b/src/gtk-helpers/problem_details_dialog.c new file mode 100644 index 0000000..dc2362e --- /dev/null +++ b/src/gtk-helpers/problem_details_dialog.c @@ -0,0 +1,80 @@ +/* + Copyright (C) 2014 ABRT Team + Copyright (C) 2014 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "problem_details_dialog.h" +#include "internal_libreport_gtk.h" +#include "internal_libreport.h" + +GtkWidget * +problem_details_dialog_new(problem_data_t *problem, GtkWindow *parent) +{ + INITIALIZE_LIBREPORT(); + + GtkWidget *dialog = gtk_dialog_new_with_buttons( + _("Problem details"), + parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + _("OK"), + GTK_RESPONSE_NONE, + NULL + ); + + gtk_window_set_default_size(GTK_WINDOW(dialog), 800, 600); + + g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); + + ProblemDetailsWidget *details = problem_details_widget_new(problem); + + GtkWidget *scrolled = gtk_scrolled_window_new(NULL, NULL); + gtk_widget_set_halign(scrolled, GTK_ALIGN_FILL); + gtk_widget_set_valign(scrolled, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(scrolled, TRUE); + gtk_widget_set_vexpand(scrolled, TRUE); + + gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(details)); + + GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(content_area), GTK_WIDGET(scrolled)); + + gtk_widget_show_all(dialog); + + return dialog; +} + +GtkWidget * +problem_details_dialog_new_for_dir(const char *dir, GtkWindow *parent) +{ + INITIALIZE_LIBREPORT(); + + struct dump_dir *dd = dd_opendir(dir, DD_OPEN_READONLY); + if (!dd) + return NULL; + + problem_data_t *problem = create_problem_data_from_dump_dir(dd); + problem_data_add_text_noteditable(problem, CD_DUMPDIR, dir); + + dd_close(dd); + + GtkWidget *dialog = problem_details_dialog_new(problem, parent); + + g_signal_connect_swapped(dialog, "destroy", G_CALLBACK(problem_data_free), problem); + + return dialog; +} + diff --git a/src/gtk-helpers/problem_details_dialog.h b/src/gtk-helpers/problem_details_dialog.h new file mode 100644 index 0000000..e8ba8ad --- /dev/null +++ b/src/gtk-helpers/problem_details_dialog.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2014 ABRT Team + Copyright (C) 2014 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef _PROBLEM_DETAILS_DIALOG_H +#define _PROBLEM_DETAILS_DIALOG_H + +#include +#include "problem_data.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +GtkWidget *problem_details_dialog_new(problem_data_t *problem, GtkWindow *parent); +GtkWidget *problem_details_dialog_new_for_dir(const char *dir, GtkWindow *parent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _PROBLEM_DETAILS_DIALOG_H */ + diff --git a/src/gtk-helpers/problem_details_widget.c b/src/gtk-helpers/problem_details_widget.c new file mode 100644 index 0000000..2cb3206 --- /dev/null +++ b/src/gtk-helpers/problem_details_widget.c @@ -0,0 +1,375 @@ +/* + Copyright (C) 2014 ABRT Team + Copyright (C) 2014 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "problem_details_widget.h" +#include "internal_libreport_gtk.h" +#include "internal_libreport.h" + +#define PROBLEM_DETAILS_WIDGET_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_PROBLEM_DETAILS_WIDGET, ProblemDetailsWidgetPrivate)) + +#define EXPLICIT_ITEMS \ + CD_DUMPDIR, \ + FILENAME_TIME, \ + FILENAME_LAST_OCCURRENCE, \ + FILENAME_UID, \ + FILENAME_USERNAME, \ + FILENAME_TYPE, \ + FILENAME_COMMENT, \ + FILENAME_ANALYZER + +#define ORDERED_ITEMS \ + FILENAME_EXPLOITABLE, \ + FILENAME_NOT_REPORTABLE, \ + FILENAME_REASON, \ + FILENAME_BACKTRACE, \ + FILENAME_CRASH_FUNCTION, \ + FILENAME_CMDLINE, \ + FILENAME_EXECUTABLE, \ + FILENAME_PACKAGE, \ + FILENAME_COMPONENT, \ + FILENAME_PID, \ + FILENAME_PWD, \ + FILENAME_HOSTNAME, \ + FILENAME_COUNT + +static const char *items_orderlist[] = { + ORDERED_ITEMS, + NULL, +}; + +static const char *items_auto_blacklist[] = { + EXPLICIT_ITEMS, + ORDERED_ITEMS, + FILENAME_PKG_NAME, + FILENAME_PKG_VERSION, + FILENAME_PKG_RELEASE, + FILENAME_PKG_ARCH, + FILENAME_PKG_EPOCH, + NULL, +}; + +struct ProblemDetailsWidgetPrivate { + PangoFontDescription *font; + gulong rows; + problem_data_t *problem_data; +}; + +G_DEFINE_TYPE(ProblemDetailsWidget, problem_details_widget, GTK_TYPE_GRID) + +static void problem_details_widget_finalize(GObject *object); + +static void +problem_details_widget_class_init(ProblemDetailsWidgetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->finalize = problem_details_widget_finalize; + + g_type_class_add_private(klass, sizeof(ProblemDetailsWidgetPrivate)); +} + +static void +problem_details_widget_finalize(GObject *object) +{ + ProblemDetailsWidget *self; + + self = PROBLEM_DETAILS_WIDGET(object); + + self->priv->problem_data = (void *)0xdeadbeaf; + + G_OBJECT_CLASS(problem_details_widget_parent_class)->finalize(object); +} + +static gulong +problem_details_widget_append_row(ProblemDetailsWidget *self) +{ + gtk_grid_insert_row(GTK_GRID(self), self->priv->rows); + return self->priv->rows++; +} + +static void +problem_details_widget_add_single_line(ProblemDetailsWidget *self, const char *name, const char *content) +{ + GtkWidget *label = gtk_label_new(name); + gtk_widget_set_halign(label, GTK_ALIGN_START); + gtk_widget_set_valign(label, GTK_ALIGN_START); + gtk_widget_set_margin_start(label, 20); + gtk_widget_set_margin_end(label, 20); + + GtkWidget *value = gtk_label_new(content); + gtk_label_set_selectable(GTK_LABEL(value), TRUE); + gtk_label_set_line_wrap(GTK_LABEL(value), TRUE); + gtk_label_set_line_wrap_mode(GTK_LABEL(value), GTK_WRAP_WORD); + gtk_widget_set_halign(value, GTK_ALIGN_START); + gtk_widget_set_hexpand(value, TRUE); + gtk_widget_set_margin_start(value, 5); + gtk_widget_override_font(GTK_WIDGET(value), self->priv->font); + + const gulong row = problem_details_widget_append_row(self); + + gtk_grid_attach(GTK_GRID(self), label, 0, row, 1, 1); + gtk_grid_attach(GTK_GRID(self), value, 1, row, 1, 1); +} + +static void +problem_details_widget_add_multi_line(ProblemDetailsWidget *self, const char *name, const char *content) +{ +#if 0 + GtkWidget *value = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(value), FALSE); + + if (strcmp(name, FILENAME_COMMENT) == 0 + || strcmp(name, FILENAME_REASON) == 0) + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(value), GTK_WRAP_WORD); + + reload_text_to_text_view(GTK_TEXT_VIEW(value), content); +#else + GtkWidget *value = gtk_label_new(content); + gtk_widget_set_halign(value, GTK_ALIGN_START); + + if (strcmp(name, FILENAME_COMMENT) == 0 + || strcmp(name, FILENAME_REASON) == 0) + { + gtk_label_set_line_wrap(GTK_LABEL(value), TRUE); + gtk_label_set_line_wrap_mode(GTK_LABEL(value), GTK_WRAP_WORD); + gtk_widget_set_margin_bottom(value, 12); + } + + gtk_label_set_selectable(GTK_LABEL(value), TRUE); +#endif + + gtk_widget_override_font(GTK_WIDGET(value), self->priv->font); + + GtkWidget *expander = gtk_expander_new(name); + gtk_widget_set_hexpand(expander, TRUE); + gtk_container_add(GTK_CONTAINER(expander), value); + + const gulong row = problem_details_widget_append_row(self); + + gtk_grid_attach(GTK_GRID(self), expander, 0, row, 2, 1); +} + +static void +problem_details_widget_add_binary(ProblemDetailsWidget *self, const char *label, const char *path) +{ + struct stat statbuf; + statbuf.st_size = 0; + + if (stat(path, &statbuf) != 0) + { + log("File '%s' does not exist", path); + return; + } + + gchar *size = g_format_size_full((long long)statbuf.st_size, G_FORMAT_SIZE_IEC_UNITS); + char *msg = xasprintf(_("$DATA_DIRECTORY/%s (binary file, %s)"), label, size); + problem_details_widget_add_single_line(self, label, msg); + free(msg); + g_free(size); +} + +static void +problem_details_widget_add_time_stamp(ProblemDetailsWidget *self, const char *label, const char *stamp) +{ + struct tm tm; + memset(&tm, 0, sizeof(struct tm)); + + const char *ret = strptime(stamp, "%s", &tm); + + if (ret == NULL || ret[0] != '\0') + return; + + char buf[255]; + strftime(buf, sizeof(buf), "%F %T", &tm); + + problem_details_widget_add_single_line(self, label, buf); +} + +static void +problem_details_widget_add_problem_item(ProblemDetailsWidget *self, const char *name, problem_item *item) +{ + if (item->flags & CD_FLAG_TXT) + { + if (strchr(item->content, '\n') == NULL) + problem_details_widget_add_single_line(self, name, item->content); + else + problem_details_widget_add_multi_line(self, name, item->content); + } + else if (item->flags & CD_FLAG_BIN) + problem_details_widget_add_binary(self, name, item->content); + else + log("Unsupported file type"); +} + +/* Callback for GHashTable */ +static void +problem_data_entry_to_grid_row_one_line(const char *item_name, problem_item *item, ProblemDetailsWidget *self) +{ + if (((item->flags & CD_FLAG_TXT) && (strchr(item->content, '\n') == NULL)) + && !is_in_string_list(item_name, (char **)items_auto_blacklist)) + problem_details_widget_add_single_line(self, item_name, item->content); +} + +static void +problem_data_entry_to_grid_row_multi_line(const char *item_name, problem_item *item, ProblemDetailsWidget *self) +{ + if (((item->flags & CD_FLAG_TXT) && (strchr(item->content, '\n') != NULL)) + && !is_in_string_list(item_name, (char **)items_auto_blacklist)) + problem_details_widget_add_multi_line(self, item_name, item->content); +} + +static void +problem_data_entry_to_grid_row_binary(const char *item_name, problem_item *item, ProblemDetailsWidget *self) +{ + if ((item->flags & CD_FLAG_BIN) + && !is_in_string_list(item_name, (char **)items_auto_blacklist)) + problem_details_widget_add_binary(self, item_name, item->content); +} + +static void +problem_details_widget_populate(ProblemDetailsWidget *self) +{ + { /* Explicit order */ + for (const char **iter = items_orderlist; *iter; ++iter) + { + struct problem_item *item = problem_data_get_item_or_NULL( + self->priv->problem_data, *iter); + + if (item == NULL) + continue; + + problem_details_widget_add_problem_item(self, *iter, item); + } + } + + { /* comment: */ + const char *dd = problem_data_get_content_or_NULL( + self->priv->problem_data, FILENAME_COMMENT); + if (dd) + problem_details_widget_add_multi_line(self, FILENAME_COMMENT, dd); + } + + { /* First occurence: 2014-08-26 11:08 */ + const char *ts = problem_data_get_content_or_NULL( + self->priv->problem_data, FILENAME_TIME); + if (ts) + problem_details_widget_add_time_stamp(self, "first_occurence", ts); + } + + { /* Last occurence: 2014-08-27 11:08 */ + const char *ts = problem_data_get_content_or_NULL( + self->priv->problem_data, FILENAME_LAST_OCCURRENCE); + if (ts) + problem_details_widget_add_time_stamp(self, "last_occurence", ts); + } + + { /* User: login(UID) */ + const char *uid = problem_data_get_content_or_NULL( + self->priv->problem_data, FILENAME_UID); + + const char *username = problem_data_get_content_or_NULL( + self->priv->problem_data, "username"); + + char *line = NULL; + if (uid && username) + line = xasprintf("%s (%s)", username, uid); + else if (!uid && !username) + line = xstrdup("unknown user"); + else + line = xasprintf("%s", uid ? uid : username); + + problem_details_widget_add_single_line(self, "user", line); + } + + { /* Type/Analyzer: CCpp */ + const char *type = problem_data_get_content_or_NULL( + self->priv->problem_data, FILENAME_TYPE); + const char *analyzer = problem_data_get_content_or_NULL( + self->priv->problem_data, FILENAME_ANALYZER); + + char *label = NULL; + char *line = NULL; + if (type != NULL && analyzer != NULL) + { + if (strcmp(type, analyzer) != 0) + { + label = xstrdup("type/analyzer"); + line = xasprintf("%s/%s", type, analyzer); + } + else + { + label = xstrdup("type"); + line = xstrdup(type); + } + } + else + { + label = xstrdup(type ? "type" : "anlyzer"); + line = xstrdup(type ? type : analyzer); + } + + problem_details_widget_add_single_line(self, label, line); + + free(line); + free(label); + } + + g_hash_table_foreach(self->priv->problem_data, + (GHFunc)problem_data_entry_to_grid_row_one_line, self); + + { /* data directory: */ + const char *dd = problem_data_get_content_or_NULL( + self->priv->problem_data, CD_DUMPDIR); + if (dd) + problem_details_widget_add_single_line(self, "data_directory", dd); + + /* show binaries below the data_directory entry */ + g_hash_table_foreach(self->priv->problem_data, + (GHFunc)problem_data_entry_to_grid_row_binary, self); + } + + g_hash_table_foreach(self->priv->problem_data, + (GHFunc)problem_data_entry_to_grid_row_multi_line, self); +} + +static void +problem_details_widget_init(ProblemDetailsWidget *self) +{ + self->priv = PROBLEM_DETAILS_WIDGET_GET_PRIVATE(self); + self->priv->font = pango_font_description_from_string("monospace"); + self->priv->rows = 0; + self->priv->problem_data = NULL; +} + +ProblemDetailsWidget * +problem_details_widget_new(problem_data_t *problem) +{ + INITIALIZE_LIBREPORT(); + + GObject *object = g_object_new(TYPE_PROBLEM_DETAILS_WIDGET, NULL); + ProblemDetailsWidget *self = PROBLEM_DETAILS_WIDGET(object); + self->priv->problem_data = problem; + + problem_details_widget_populate(self); + gtk_widget_show_all(GTK_WIDGET(self)); + + return self; +} + diff --git a/src/gtk-helpers/problem_details_widget.h b/src/gtk-helpers/problem_details_widget.h new file mode 100644 index 0000000..c736a5d --- /dev/null +++ b/src/gtk-helpers/problem_details_widget.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2014 ABRT Team + Copyright (C) 2014 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef _PROBLEM_DETAILS_WIDGET_H +#define _PROBLEM_DETAILS_WIDGET_H + +#include +#include "problem_data.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +G_BEGIN_DECLS + +#define TYPE_PROBLEM_DETAILS_WIDGET (problem_details_widget_get_type()) +#define PROBLEM_DETAILS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PROBLEM_DETAILS_WIDGET, ProblemDetailsWidget)) +#define PROBLEM_DETAILS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PROBLEM_DETAILS_WIDGET, ProblemDetailsWidgetClass)) +#define IS_PROBLEM_DETAILS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PROBLEM_DETAILS_WIDGET)) +#define IS_PROBLEM_DETAILS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PROBLEM_DETAILS_WIDGET)) +#define PROBLEM_DETAILS_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PROBLEM_DETAILS_WIDGET, ProblemDetailsWidgetClass)) + +typedef struct _ProblemDetailsWidget ProblemDetailsWidget; +typedef struct _ProblemDetailsWidgetClass ProblemDetailsWidgetClass; +typedef struct ProblemDetailsWidgetPrivate ProblemDetailsWidgetPrivate; + +struct _ProblemDetailsWidget { + GtkGrid parent_instance; + ProblemDetailsWidgetPrivate *priv; +}; + +struct _ProblemDetailsWidgetClass { + GtkGridClass parent_class; +}; + +GType problem_details_widget_get_type (void) G_GNUC_CONST; + +ProblemDetailsWidget *problem_details_widget_new(problem_data_t *problem); + +G_END_DECLS + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _PROBLEM_DETAILS_WIDGET_H */ + diff --git a/src/gtk-helpers/utils.c b/src/gtk-helpers/utils.c new file mode 100644 index 0000000..4ba2c0e --- /dev/null +++ b/src/gtk-helpers/utils.c @@ -0,0 +1,25 @@ +#include "internal_libreport_gtk.h" + +void reload_text_to_text_view(GtkTextView *tv, const char *text) +{ + GtkTextBuffer *tb = gtk_text_view_get_buffer(tv); + GtkTextIter beg_iter, end_iter; + gtk_text_buffer_get_iter_at_offset(tb, &beg_iter, 0); + gtk_text_buffer_get_iter_at_offset(tb, &end_iter, -1); + gtk_text_buffer_delete(tb, &beg_iter, &end_iter); + + if (!text) + return; + + const gchar *end; + while (!g_utf8_validate(text, -1, &end)) + { + gtk_text_buffer_insert_at_cursor(tb, text, end - text); + char buf[8]; + unsigned len = snprintf(buf, sizeof(buf), "<%02X>", (unsigned char)*end); + gtk_text_buffer_insert_at_cursor(tb, buf, len); + text = end + 1; + } + + gtk_text_buffer_insert_at_cursor(tb, text, strlen(text)); +} diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c index 525d275..54b9b10 100644 --- a/src/gui-wizard-gtk/wizard.c +++ b/src/gui-wizard-gtk/wizard.c @@ -393,31 +393,12 @@ static void load_text_to_text_view(GtkTextView *tv, const char *name) /* a result of xstrdup() is freed */ g_hash_table_insert(g_loaded_texts, (gpointer)xstrdup(name), (gpointer)1); - GtkTextBuffer *tb = gtk_text_view_get_buffer(tv); - const char *str = g_cd ? problem_data_get_content_or_NULL(g_cd, name) : NULL; /* Bad: will choke at any text with non-Unicode parts: */ /* gtk_text_buffer_set_text(tb, (str ? str : ""), -1);*/ /* Start torturing ourself instead: */ - GtkTextIter beg_iter, end_iter; - gtk_text_buffer_get_iter_at_offset(tb, &beg_iter, 0); - gtk_text_buffer_get_iter_at_offset(tb, &end_iter, -1); - gtk_text_buffer_delete(tb, &beg_iter, &end_iter); - - if (!str) - return; - - const gchar *end; - while (!g_utf8_validate(str, -1, &end)) - { - gtk_text_buffer_insert_at_cursor(tb, str, end - str); - char buf[8]; - unsigned len = snprintf(buf, sizeof(buf), "<%02X>", (unsigned char)*end); - gtk_text_buffer_insert_at_cursor(tb, buf, len); - str = end + 1; - } - gtk_text_buffer_insert_at_cursor(tb, str, strlen(str)); + reload_text_to_text_view(tv, str); } static gchar *get_malloced_string_from_text_view(GtkTextView *tv) -- 1.8.3.1