From 4d571e174c136b874978457ea003edd41dc81fba Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 16 Jun 2011 18:53:08 +0200 Subject: abrt-gui: merge source into one file. No functional changes text data bss dec hex filename 21617 1068 40 22725 58c5 abrt-gui 21260 1060 40 22360 5758 abrt-gui.new Signed-off-by: Denys Vlasenko --- src/gui-gtk/Makefile.am | 1 - src/gui-gtk/abrt-gtk.c | 526 ------------------------------------------------ src/gui-gtk/abrt-gtk.h | 26 --- src/gui-gtk/main.c | 514 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 512 insertions(+), 555 deletions(-) delete mode 100644 src/gui-gtk/abrt-gtk.c delete mode 100644 src/gui-gtk/abrt-gtk.h diff --git a/src/gui-gtk/Makefile.am b/src/gui-gtk/Makefile.am index d6387f87..50250828 100644 --- a/src/gui-gtk/Makefile.am +++ b/src/gui-gtk/Makefile.am @@ -1,7 +1,6 @@ bin_PROGRAMS = abrt-gui abrt_gui_SOURCES = \ - abrt-gtk.h abrt-gtk.c \ main.c abrt_gui_CFLAGS = \ -I$(srcdir)/../include \ diff --git a/src/gui-gtk/abrt-gtk.c b/src/gui-gtk/abrt-gtk.c deleted file mode 100644 index d61ef4e6..00000000 --- a/src/gui-gtk/abrt-gtk.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - Copyright (C) 2011 ABRT Team - Copyright (C) 2011 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 -#include -#include "abrtlib.h" -#include "abrt-gtk.h" -#include "libreport-gtk.h" - -static const char help_uri[] = "http://docs.fedoraproject.org/en-US/" - "Fedora/14/html/Deployment_Guide/ch-abrt.html"; - -static GtkListStore *s_dumps_list_store; -static GtkWidget *s_treeview; -static GtkWidget *g_main_window; -static GtkWidget *s_report_window; - -enum -{ - COLUMN_REPORTED, - COLUMN_REASON, - COLUMN_DIRNAME, - COLUMN_LATEST_CRASH_STR, - COLUMN_LATEST_CRASH, - COLUMN_DUMP_DIR, - NUM_COLUMNS -}; - -void add_directory_to_dirlist(const char *dirname) -{ - /* Silently ignore *any* errors, not only EACCES. - * We saw "lock file is locked by process PID" error - * when we raced with wizard. - */ - int sv_logmode = logmode; - logmode = 0; - struct dump_dir *dd = dd_opendir(dirname, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES); - logmode = sv_logmode; - if (!dd) - return; - - time_t time = atoi(dd_load_text(dd, FILENAME_TIME)); - struct tm *ptm = localtime(&time); - char time_buf[60]; - size_t time_len = strftime(time_buf, sizeof(time_buf)-1, "%c", ptm); - time_buf[time_len] = '\0'; - - char *msg = dd_load_text_ext(dd, FILENAME_REPORTED_TO, 0 - | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE - | DD_FAIL_QUIETLY_ENOENT - | DD_FAIL_QUIETLY_EACCES - ); - const char *reported = (msg ? GTK_STOCK_YES : GTK_STOCK_NO); - free(msg); - char *reason = dd_load_text(dd, FILENAME_REASON); - - GtkTreeIter iter; - gtk_list_store_append(s_dumps_list_store, &iter); - gtk_list_store_set(s_dumps_list_store, &iter, - COLUMN_REPORTED, reported, - COLUMN_REASON, reason, - COLUMN_DIRNAME, dd->dd_dirname, - //OPTION: time format - COLUMN_LATEST_CRASH_STR, time_buf, - COLUMN_LATEST_CRASH, (int)time, - COLUMN_DUMP_DIR, dirname, - -1); - free(reason); - - dd_close(dd); - VERB1 log("added: %s", dirname); -} - -void rescan_dirs_and_add_to_dirlist(void) -{ - gtk_list_store_clear(s_dumps_list_store); - scan_dirs_and_add_to_dirlist(); -} - - -/* create_main_window and helpers */ - -static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - if (selection) - { - GtkTreeIter iter; - GtkTreeModel *store = gtk_tree_view_get_model(treeview); - if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) - { - GValue d_dir = { 0 }; - gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir); - - const char *dirname = g_value_get_string(&d_dir); - report_problem_in_dir(dirname, LIBREPORT_ANALYZE | LIBREPORT_NOWAIT); - } - } -} - -static void on_btn_report_cb(GtkButton *button, gpointer user_data) -{ - on_row_activated_cb(GTK_TREE_VIEW(s_treeview), NULL, NULL, NULL); -} - -static void delete_report(GtkTreeView *treeview) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - if (selection) - { - GtkTreeIter iter; - GtkTreeModel *store = gtk_tree_view_get_model(treeview); - if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) - { - GtkTreePath *old_path = gtk_tree_model_get_path(store, &iter); - - GValue d_dir = { 0 }; - gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir); - const char *dump_dir_name = g_value_get_string(&d_dir); - - VERB1 log("Deleting '%s'", dump_dir_name); - if (delete_dump_dir_possibly_using_abrtd(dump_dir_name) == 0) - { - gtk_list_store_remove(s_dumps_list_store, &iter); - } - else - { - /* Strange. Deletion did not succeed. Someone else deleted it? - * Rescan the whole list */ - rescan_dirs_and_add_to_dirlist(); - } - - /* Try to retain the same cursor position */ - sanitize_cursor(old_path); - gtk_tree_path_free(old_path); - } - } -} - -static gint on_key_press_event_cb(GtkTreeView *treeview, GdkEventKey *key, gpointer unused) -{ - int k = key->keyval; - - if (k == GDK_Delete || k == GDK_KP_Delete) - { - delete_report(treeview); - return TRUE; - } - return FALSE; -} - -static void on_btn_delete_cb(GtkButton *button, gpointer unused) -{ - delete_report(GTK_TREE_VIEW(s_treeview)); -} - -static void on_btn_online_help_cb(GtkButton *button, gpointer unused) -{ - gtk_show_uri(NULL, help_uri, GDK_CURRENT_TIME, NULL); -} - -static void on_menu_help_cb(GtkMenuItem *menuitem, gpointer unused) -{ - gtk_show_uri(NULL, help_uri, GDK_CURRENT_TIME, NULL); -} - -static void on_button_send_cb(GtkWidget *button, gpointer data) -{ - GtkTextView *tev = GTK_TEXT_VIEW(data); - GtkTextBuffer *buf = gtk_text_view_get_buffer(tev); - GtkTextIter it_start; - GtkTextIter it_end; - gtk_text_buffer_get_start_iter(buf, &it_start); - gtk_text_buffer_get_end_iter(buf, &it_end); - gchar *text = gtk_text_buffer_get_text(buf, - &it_start, - &it_end, - false); - - problem_data_t *pd = new_problem_data(); - - if (text[0]) - { - add_to_problem_data(pd, "description", text); - } - - /* why it doesn't want to hide before report ends? */ - gtk_widget_destroy(s_report_window); - -//TODO: LIBREPORT_WAIT is used here only because we don't want to leave temp dir. -//Change to LIBREPORT_NOWAIT when libreport is taught to -//properly delete temp dir even with LIBREPORT_NOWAIT. - int status = report_problem_in_memory(pd, LIBREPORT_WAIT); - VERB1 log("Reporting finished with status %i", status); - free_problem_data(pd); -} - -static void on_menu_report_cb(GtkMenuItem *menuitem, gpointer unused) -{ - s_report_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(s_report_window), _("Problem description")); - gtk_window_set_default_size(GTK_WINDOW(s_report_window), 400, 400); - GtkWidget *vbox = gtk_vbox_new(false, 0); - GtkWidget *button_send = gtk_button_new_with_label(_("Send")); - GtkWidget *tev = gtk_text_view_new(); - g_signal_connect(button_send, "clicked", G_CALLBACK(on_button_send_cb), tev); - - gtk_box_pack_start(GTK_BOX(vbox), tev, true, true, 0); - gtk_box_pack_start(GTK_BOX(vbox), button_send, false, false, 5); - - gtk_container_add(GTK_CONTAINER(s_report_window), vbox); - - gtk_widget_show_all(s_report_window); -} - -static void on_menu_about_cb(GtkMenuItem *menuitem, gpointer unused) -{ - static const char copyright_str[] = "Copyright © 2009, 2010, 2011 Red Hat, Inc"; - - static const char license_str[] = "This program is free software; you can redistribut" - "e 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 Li" - "cense, or (at your option) any later version.\n\nThis program is distrib" - "uted in the hope that it will be useful, but WITHOUT ANY WARRANTY; witho" - "ut even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICU" - "LAR PURPOSE. See the GNU General Public License for more details.\n\nYo" - "u should have received a copy of the GNU General Public License along wi" - "th this program. If not, see ."; - - static const char website_url[] = "https://fedorahosted.org/abrt/"; - - static const char *authors[] = { - "Anton Arapov ", - "Karel Klic ", - "Jiri Moskovcak ", - "Nikola Pajkovsky ", - "Denys Vlasenko ", - "Michal Toman ", - "Zdenek Prikryl", - NULL - }; - - static const char *artists[] = { - "Patrick Connelly ", - "Máirín Duffy ", - "Lapo Calamandrei", - "Jakub Steinar ", - NULL - }; - - GtkWidget *about_d = gtk_about_dialog_new(); - - gtk_window_set_icon_name(GTK_WINDOW(about_d), "abrt"); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_d), VERSION); - gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(about_d), "abrt"); - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about_d), "ABRT"); - gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_d), copyright_str); - gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about_d), license_str); - gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(about_d),true); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_d), website_url); - gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about_d), authors); - gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about_d), artists); - gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about_d), _("translator-credits")); - - gtk_window_set_transient_for(GTK_WINDOW(about_d), GTK_WINDOW(g_main_window)); - - gtk_dialog_run(GTK_DIALOG(about_d)); - gtk_widget_hide(GTK_WIDGET(about_d)); -} - -static void show_events_list_dialog_cb(GtkMenuItem *menuitem, gpointer user_data) -{ - show_events_list_dialog(GTK_WINDOW(g_main_window)); -} - -static void add_columns(GtkTreeView *treeview) -{ - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes(_("Reported"), - renderer, - "stock_id", - COLUMN_REPORTED, - NULL); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_sort_column_id(column, COLUMN_REPORTED); - gtk_tree_view_append_column(treeview, column); - - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Problem"), - renderer, - "text", - COLUMN_REASON, - NULL); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_sort_column_id(column, COLUMN_REASON); - gtk_tree_view_append_column(treeview, column); - - /* - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Stored in"), - renderer, - "text", - COLUMN_DIRNAME, - NULL); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_sort_column_id(column, COLUMN_DIRNAME); - gtk_tree_view_append_column(treeview, column); - */ - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Last occurrence"), - renderer, - "text", - COLUMN_LATEST_CRASH_STR, - NULL); - gtk_tree_view_column_set_sort_column_id(column, COLUMN_LATEST_CRASH); - gtk_tree_view_append_column(treeview, column); -} - -GtkWidget *create_menu(void) -{ - /* main bar */ - GtkWidget *menu = gtk_menu_bar_new(); - GtkWidget *file_item = gtk_menu_item_new_with_mnemonic(_("_File")); - GtkWidget *edit_item = gtk_menu_item_new_with_mnemonic(_("_Edit")); - GtkWidget *help_item = gtk_menu_item_new_with_mnemonic(_("_Help")); - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), file_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), edit_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), help_item); - - /* file submenu */ - GtkWidget *file_submenu = gtk_menu_new(); - GtkWidget *quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(file_submenu), quit_item); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_submenu); - - g_signal_connect(quit_item, "activate", >k_main_quit, NULL); - - /* edit submenu */ - GtkWidget *edit_submenu = gtk_menu_new(); - GtkWidget *plugins_item = gtk_menu_item_new_with_mnemonic(_("_Event configuration")); - //GtkWidget *preferences_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), plugins_item); - //gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), preferences_item); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_submenu); - - g_signal_connect(plugins_item, "activate", G_CALLBACK(show_events_list_dialog_cb), NULL); - - /* help submenu */ - GtkWidget *help_submenu = gtk_menu_new(); - GtkWidget *online_help_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP, NULL); - GtkWidget *report_problem_item = gtk_menu_item_new_with_label(_("Report problem with ABRT")); - GtkWidget *about_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), online_help_item); - gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), report_problem_item); - gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), about_item); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_item), help_submenu); - - g_signal_connect(online_help_item, "activate", G_CALLBACK(on_menu_help_cb), NULL); - g_signal_connect(report_problem_item, "activate", G_CALLBACK(on_menu_report_cb), NULL); - g_signal_connect(about_item, "activate", G_CALLBACK(on_menu_about_cb), NULL); - - return menu; -} - -GtkWidget *create_main_window(void) -{ - /* Main window */ - g_main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size(GTK_WINDOW(g_main_window), 700, 700); - gtk_window_set_title(GTK_WINDOW(g_main_window), _("Automatic Bug Reporting Tool")); - gtk_window_set_default_icon_name("abrt"); - - GtkWidget *main_vbox = gtk_vbox_new(false, 0); - - /* Scrolled region inside main window */ - GtkWidget *scroll_win = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_win), - GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_box_pack_start(GTK_BOX(main_vbox), create_menu(), false, false, 0); - gtk_box_pack_start(GTK_BOX(main_vbox), scroll_win, true, true, 0); - gtk_container_add(GTK_CONTAINER(g_main_window), main_vbox); - - /* Tree view inside scrolled region */ - s_treeview = gtk_tree_view_new(); - g_object_set(s_treeview, "rules-hint", 1, NULL); /* use alternating colors */ - add_columns(GTK_TREE_VIEW(s_treeview)); - gtk_container_add(GTK_CONTAINER(scroll_win), s_treeview); - - /* Create data store for the list and attach it */ - s_dumps_list_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, /* reported */ - G_TYPE_STRING, /* executable */ - G_TYPE_STRING, /* hostname */ - G_TYPE_STRING, /* time */ - G_TYPE_INT, /* unix time - used for sort */ - G_TYPE_STRING, /* dump dir path */ - G_TYPE_STRING);/* row background */ - - //FIXME: configurable!! - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_dumps_list_store), - COLUMN_LATEST_CRASH, - GTK_SORT_DESCENDING); - - gtk_tree_view_set_model(GTK_TREE_VIEW(s_treeview), GTK_TREE_MODEL(s_dumps_list_store)); - - /* buttons are homogenous so set size only for one button and it will - * work for the rest buttons in same gtk_hbox_new() */ - GtkWidget *btn_report = gtk_button_new_from_stock(GTK_STOCK_OPEN); - gtk_widget_set_size_request(btn_report, 200, 30); - - GtkWidget *btn_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE); - - GtkWidget *hbox_report_delete = gtk_hbox_new(true, 4); - gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_delete, true, true, 0); - gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_report, true, true, 0); - - GtkWidget *halign = gtk_alignment_new(1, 0, 0, 0); - gtk_container_add(GTK_CONTAINER(halign), hbox_report_delete); - - GtkWidget *hbox_help_close = gtk_hbutton_box_new(); - GtkWidget *btn_online_help = gtk_button_new_with_mnemonic(_("Online _Help")); - GtkWidget *btn_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - gtk_box_pack_end(GTK_BOX(hbox_help_close), btn_online_help, false, false, 0); - gtk_box_pack_end(GTK_BOX(hbox_help_close), btn_close, false, false, 0); - - gtk_box_pack_start(GTK_BOX(main_vbox), halign, false, false, 10); - gtk_box_pack_start(GTK_BOX(main_vbox), hbox_help_close, false, false, 10); - - /* Double click/Enter handler */ - g_signal_connect(s_treeview, "row-activated", G_CALLBACK(on_row_activated_cb), NULL); - g_signal_connect(btn_report, "clicked", G_CALLBACK(on_btn_report_cb), NULL); - /* Delete handler */ - g_signal_connect(s_treeview, "key-press-event", G_CALLBACK(on_key_press_event_cb), NULL); - g_signal_connect(btn_delete, "clicked", G_CALLBACK(on_btn_delete_cb), NULL); - /* Quit when user closes the main window */ - g_signal_connect(g_main_window, "destroy", gtk_main_quit, NULL); - /* Quit when user click on Cancel button */ - g_signal_connect(btn_close, "clicked", gtk_main_quit, NULL); - /* Show online help */ - g_signal_connect(btn_online_help, "clicked", G_CALLBACK(on_btn_online_help_cb), NULL); - - return g_main_window; -} - -GtkTreePath *get_cursor(void) -{ - GtkTreeView *treeview = GTK_TREE_VIEW(s_treeview); - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - if (selection) - { - GtkTreeIter iter; - GtkTreeModel *store = gtk_tree_view_get_model(treeview); - if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) - { - return gtk_tree_model_get_path(store, &iter); - } - } - return NULL; -} - -void sanitize_cursor(GtkTreePath *preferred_path) -{ - GtkTreePath *path; - - gtk_tree_view_get_cursor(GTK_TREE_VIEW(s_treeview), &path, /* GtkTreeViewColumn** */ NULL); - if (path) - { - /* Cursor exists already */ - goto ret; - } - - if (preferred_path) - { - /* Try to position cursor on preferred_path */ - gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_treeview), preferred_path, - /* GtkTreeViewColumn *focus_column */ NULL, /* start_editing */ false); - - /* Did it work? */ - gtk_tree_view_get_cursor(GTK_TREE_VIEW(s_treeview), &path, /* GtkTreeViewColumn** */ NULL); - if (path) /* yes */ - goto ret; - } - - /* Try to position cursor on 1st element */ - GtkTreeIter iter; - if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(s_dumps_list_store), &iter)) - { - /* We have at least one element, put cursor on it */ - - /* Get path from iter pointing to 1st element */ - path = gtk_tree_model_get_path(GTK_TREE_MODEL(s_dumps_list_store), &iter); - - /* Use it to set cursor */ - gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_treeview), path, - /* GtkTreeViewColumn *focus_column */ NULL, /* start_editing */ false); - } - /* else we have no elements */ - - ret: - gtk_tree_path_free(path); - - /* Without this, the *header* of the list gets the focus. Ugly. */ - gtk_widget_grab_focus(s_treeview); -} diff --git a/src/gui-gtk/abrt-gtk.h b/src/gui-gtk/abrt-gtk.h deleted file mode 100644 index 259797fa..00000000 --- a/src/gui-gtk/abrt-gtk.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright (C) 2011 ABRT Team - Copyright (C) 2011 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. -*/ -GtkWidget *create_main_window(void); -void add_directory_to_dirlist(const char *dirname); -/* May return NULL */ -GtkTreePath *get_cursor(void); -void sanitize_cursor(GtkTreePath *preferred_path); -void rescan_dirs_and_add_to_dirlist(void); - -void scan_dirs_and_add_to_dirlist(void); diff --git a/src/gui-gtk/main.c b/src/gui-gtk/main.c index f76f62f3..2888d6d5 100644 --- a/src/gui-gtk/main.c +++ b/src/gui-gtk/main.c @@ -16,15 +16,525 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + #include +#include #include +#include #include "abrtlib.h" #include "parse_options.h" -#include "abrt-gtk.h" #if HAVE_LOCALE_H # include #endif +static void scan_dirs_and_add_to_dirlist(void); + + +static const char help_uri[] = "http://docs.fedoraproject.org/en-US/" + "Fedora/14/html/Deployment_Guide/ch-abrt.html"; + +static GtkListStore *s_dumps_list_store; +static GtkWidget *s_treeview; +static GtkWidget *g_main_window; +static GtkWidget *s_report_window; + +enum +{ + COLUMN_REPORTED, + COLUMN_REASON, + COLUMN_DIRNAME, + COLUMN_LATEST_CRASH_STR, + COLUMN_LATEST_CRASH, + COLUMN_DUMP_DIR, + NUM_COLUMNS +}; + +static void add_directory_to_dirlist(const char *dirname) +{ + /* Silently ignore *any* errors, not only EACCES. + * We saw "lock file is locked by process PID" error + * when we raced with wizard. + */ + int sv_logmode = logmode; + logmode = 0; + struct dump_dir *dd = dd_opendir(dirname, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES); + logmode = sv_logmode; + if (!dd) + return; + + time_t time = atoi(dd_load_text(dd, FILENAME_TIME)); + struct tm *ptm = localtime(&time); + char time_buf[60]; + size_t time_len = strftime(time_buf, sizeof(time_buf)-1, "%c", ptm); + time_buf[time_len] = '\0'; + + char *msg = dd_load_text_ext(dd, FILENAME_REPORTED_TO, 0 + | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE + | DD_FAIL_QUIETLY_ENOENT + | DD_FAIL_QUIETLY_EACCES + ); + const char *reported = (msg ? GTK_STOCK_YES : GTK_STOCK_NO); + free(msg); + char *reason = dd_load_text(dd, FILENAME_REASON); + + GtkTreeIter iter; + gtk_list_store_append(s_dumps_list_store, &iter); + gtk_list_store_set(s_dumps_list_store, &iter, + COLUMN_REPORTED, reported, + COLUMN_REASON, reason, + COLUMN_DIRNAME, dd->dd_dirname, + //OPTION: time format + COLUMN_LATEST_CRASH_STR, time_buf, + COLUMN_LATEST_CRASH, (int)time, + COLUMN_DUMP_DIR, dirname, + -1); + free(reason); + + dd_close(dd); + VERB1 log("added: %s", dirname); +} + +static void rescan_dirs_and_add_to_dirlist(void) +{ + gtk_list_store_clear(s_dumps_list_store); + scan_dirs_and_add_to_dirlist(); +} + + +static GtkTreePath *get_cursor(void) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(s_treeview); + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + if (selection) + { + GtkTreeIter iter; + GtkTreeModel *store = gtk_tree_view_get_model(treeview); + if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) + { + return gtk_tree_model_get_path(store, &iter); + } + } + return NULL; +} + +static void sanitize_cursor(GtkTreePath *preferred_path) +{ + GtkTreePath *path; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(s_treeview), &path, /* GtkTreeViewColumn** */ NULL); + if (path) + { + /* Cursor exists already */ + goto ret; + } + + if (preferred_path) + { + /* Try to position cursor on preferred_path */ + gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_treeview), preferred_path, + /* GtkTreeViewColumn *focus_column */ NULL, /* start_editing */ false); + + /* Did it work? */ + gtk_tree_view_get_cursor(GTK_TREE_VIEW(s_treeview), &path, /* GtkTreeViewColumn** */ NULL); + if (path) /* yes */ + goto ret; + } + + /* Try to position cursor on 1st element */ + GtkTreeIter iter; + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(s_dumps_list_store), &iter)) + { + /* We have at least one element, put cursor on it */ + + /* Get path from iter pointing to 1st element */ + path = gtk_tree_model_get_path(GTK_TREE_MODEL(s_dumps_list_store), &iter); + + /* Use it to set cursor */ + gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_treeview), path, + /* GtkTreeViewColumn *focus_column */ NULL, /* start_editing */ false); + } + /* else we have no elements */ + + ret: + gtk_tree_path_free(path); + + /* Without this, the *header* of the list gets the focus. Ugly. */ + gtk_widget_grab_focus(s_treeview); +} + + +/* create_main_window and helpers */ + +static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + if (selection) + { + GtkTreeIter iter; + GtkTreeModel *store = gtk_tree_view_get_model(treeview); + if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) + { + GValue d_dir = { 0 }; + gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir); + + const char *dirname = g_value_get_string(&d_dir); + report_problem_in_dir(dirname, LIBREPORT_ANALYZE | LIBREPORT_NOWAIT); + } + } +} + +static void on_btn_report_cb(GtkButton *button, gpointer user_data) +{ + on_row_activated_cb(GTK_TREE_VIEW(s_treeview), NULL, NULL, NULL); +} + +static void delete_report(GtkTreeView *treeview) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + if (selection) + { + GtkTreeIter iter; + GtkTreeModel *store = gtk_tree_view_get_model(treeview); + if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) + { + GtkTreePath *old_path = gtk_tree_model_get_path(store, &iter); + + GValue d_dir = { 0 }; + gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir); + const char *dump_dir_name = g_value_get_string(&d_dir); + + VERB1 log("Deleting '%s'", dump_dir_name); + if (delete_dump_dir_possibly_using_abrtd(dump_dir_name) == 0) + { + gtk_list_store_remove(s_dumps_list_store, &iter); + } + else + { + /* Strange. Deletion did not succeed. Someone else deleted it? + * Rescan the whole list */ + rescan_dirs_and_add_to_dirlist(); + } + + /* Try to retain the same cursor position */ + sanitize_cursor(old_path); + gtk_tree_path_free(old_path); + } + } +} + +static gint on_key_press_event_cb(GtkTreeView *treeview, GdkEventKey *key, gpointer unused) +{ + int k = key->keyval; + + if (k == GDK_Delete || k == GDK_KP_Delete) + { + delete_report(treeview); + return TRUE; + } + return FALSE; +} + +static void on_btn_delete_cb(GtkButton *button, gpointer unused) +{ + delete_report(GTK_TREE_VIEW(s_treeview)); +} + +static void on_btn_online_help_cb(GtkButton *button, gpointer unused) +{ + gtk_show_uri(NULL, help_uri, GDK_CURRENT_TIME, NULL); +} + +static void on_menu_help_cb(GtkMenuItem *menuitem, gpointer unused) +{ + gtk_show_uri(NULL, help_uri, GDK_CURRENT_TIME, NULL); +} + +static void on_button_send_cb(GtkWidget *button, gpointer data) +{ + GtkTextView *tev = GTK_TEXT_VIEW(data); + GtkTextBuffer *buf = gtk_text_view_get_buffer(tev); + GtkTextIter it_start; + GtkTextIter it_end; + gtk_text_buffer_get_start_iter(buf, &it_start); + gtk_text_buffer_get_end_iter(buf, &it_end); + gchar *text = gtk_text_buffer_get_text(buf, + &it_start, + &it_end, + false); + + problem_data_t *pd = new_problem_data(); + + if (text[0]) + { + add_to_problem_data(pd, "description", text); + } + + /* why it doesn't want to hide before report ends? */ + gtk_widget_destroy(s_report_window); + +//TODO: LIBREPORT_WAIT is used here only because we don't want to leave temp dir. +//Change to LIBREPORT_NOWAIT when libreport is taught to +//properly delete temp dir even with LIBREPORT_NOWAIT. + int status = report_problem_in_memory(pd, LIBREPORT_WAIT); + VERB1 log("Reporting finished with status %i", status); + free_problem_data(pd); +} + +static void on_menu_report_cb(GtkMenuItem *menuitem, gpointer unused) +{ + s_report_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(s_report_window), _("Problem description")); + gtk_window_set_default_size(GTK_WINDOW(s_report_window), 400, 400); + GtkWidget *vbox = gtk_vbox_new(false, 0); + GtkWidget *button_send = gtk_button_new_with_label(_("Send")); + GtkWidget *tev = gtk_text_view_new(); + g_signal_connect(button_send, "clicked", G_CALLBACK(on_button_send_cb), tev); + + gtk_box_pack_start(GTK_BOX(vbox), tev, true, true, 0); + gtk_box_pack_start(GTK_BOX(vbox), button_send, false, false, 5); + + gtk_container_add(GTK_CONTAINER(s_report_window), vbox); + + gtk_widget_show_all(s_report_window); +} + +static void on_menu_about_cb(GtkMenuItem *menuitem, gpointer unused) +{ + static const char copyright_str[] = "Copyright © 2009, 2010, 2011 Red Hat, Inc"; + + static const char license_str[] = "This program is free software; you can redistribut" + "e 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 Li" + "cense, or (at your option) any later version.\n\nThis program is distrib" + "uted in the hope that it will be useful, but WITHOUT ANY WARRANTY; witho" + "ut even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICU" + "LAR PURPOSE. See the GNU General Public License for more details.\n\nYo" + "u should have received a copy of the GNU General Public License along wi" + "th this program. If not, see ."; + + static const char website_url[] = "https://fedorahosted.org/abrt/"; + + static const char *authors[] = { + "Anton Arapov ", + "Karel Klic ", + "Jiri Moskovcak ", + "Nikola Pajkovsky ", + "Denys Vlasenko ", + "Michal Toman ", + "Zdenek Prikryl", + NULL + }; + + static const char *artists[] = { + "Patrick Connelly ", + "Máirín Duffy ", + "Lapo Calamandrei", + "Jakub Steinar ", + NULL + }; + + GtkWidget *about_d = gtk_about_dialog_new(); + + gtk_window_set_icon_name(GTK_WINDOW(about_d), "abrt"); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_d), VERSION); + gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(about_d), "abrt"); + gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about_d), "ABRT"); + gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_d), copyright_str); + gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about_d), license_str); + gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(about_d),true); + gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_d), website_url); + gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about_d), authors); + gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about_d), artists); + gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about_d), _("translator-credits")); + + gtk_window_set_transient_for(GTK_WINDOW(about_d), GTK_WINDOW(g_main_window)); + + gtk_dialog_run(GTK_DIALOG(about_d)); + gtk_widget_hide(GTK_WIDGET(about_d)); +} + +static void show_events_list_dialog_cb(GtkMenuItem *menuitem, gpointer user_data) +{ + show_events_list_dialog(GTK_WINDOW(g_main_window)); +} + +static void add_columns(GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes(_("Reported"), + renderer, + "stock_id", + COLUMN_REPORTED, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_REPORTED); + gtk_tree_view_append_column(treeview, column); + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Problem"), + renderer, + "text", + COLUMN_REASON, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_REASON); + gtk_tree_view_append_column(treeview, column); + + /* + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Stored in"), + renderer, + "text", + COLUMN_DIRNAME, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_DIRNAME); + gtk_tree_view_append_column(treeview, column); + */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Last occurrence"), + renderer, + "text", + COLUMN_LATEST_CRASH_STR, + NULL); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_LATEST_CRASH); + gtk_tree_view_append_column(treeview, column); +} + +static GtkWidget *create_menu(void) +{ + /* main bar */ + GtkWidget *menu = gtk_menu_bar_new(); + GtkWidget *file_item = gtk_menu_item_new_with_mnemonic(_("_File")); + GtkWidget *edit_item = gtk_menu_item_new_with_mnemonic(_("_Edit")); + GtkWidget *help_item = gtk_menu_item_new_with_mnemonic(_("_Help")); + + gtk_menu_shell_append(GTK_MENU_SHELL(menu), file_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), edit_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), help_item); + + /* file submenu */ + GtkWidget *file_submenu = gtk_menu_new(); + GtkWidget *quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(file_submenu), quit_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_submenu); + + g_signal_connect(quit_item, "activate", >k_main_quit, NULL); + + /* edit submenu */ + GtkWidget *edit_submenu = gtk_menu_new(); + GtkWidget *plugins_item = gtk_menu_item_new_with_mnemonic(_("_Event configuration")); + //GtkWidget *preferences_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), plugins_item); + //gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), preferences_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_submenu); + + g_signal_connect(plugins_item, "activate", G_CALLBACK(show_events_list_dialog_cb), NULL); + + /* help submenu */ + GtkWidget *help_submenu = gtk_menu_new(); + GtkWidget *online_help_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP, NULL); + GtkWidget *report_problem_item = gtk_menu_item_new_with_label(_("Report problem with ABRT")); + GtkWidget *about_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), online_help_item); + gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), report_problem_item); + gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), about_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_item), help_submenu); + + g_signal_connect(online_help_item, "activate", G_CALLBACK(on_menu_help_cb), NULL); + g_signal_connect(report_problem_item, "activate", G_CALLBACK(on_menu_report_cb), NULL); + g_signal_connect(about_item, "activate", G_CALLBACK(on_menu_about_cb), NULL); + + return menu; +} + +static GtkWidget *create_main_window(void) +{ + /* Main window */ + g_main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(g_main_window), 700, 700); + gtk_window_set_title(GTK_WINDOW(g_main_window), _("Automatic Bug Reporting Tool")); + gtk_window_set_default_icon_name("abrt"); + + GtkWidget *main_vbox = gtk_vbox_new(false, 0); + + /* Scrolled region inside main window */ + GtkWidget *scroll_win = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_win), + GTK_SHADOW_ETCHED_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_box_pack_start(GTK_BOX(main_vbox), create_menu(), false, false, 0); + gtk_box_pack_start(GTK_BOX(main_vbox), scroll_win, true, true, 0); + gtk_container_add(GTK_CONTAINER(g_main_window), main_vbox); + + /* Tree view inside scrolled region */ + s_treeview = gtk_tree_view_new(); + g_object_set(s_treeview, "rules-hint", 1, NULL); /* use alternating colors */ + add_columns(GTK_TREE_VIEW(s_treeview)); + gtk_container_add(GTK_CONTAINER(scroll_win), s_treeview); + + /* Create data store for the list and attach it */ + s_dumps_list_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, /* reported */ + G_TYPE_STRING, /* executable */ + G_TYPE_STRING, /* hostname */ + G_TYPE_STRING, /* time */ + G_TYPE_INT, /* unix time - used for sort */ + G_TYPE_STRING, /* dump dir path */ + G_TYPE_STRING);/* row background */ + + //FIXME: configurable!! + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_dumps_list_store), + COLUMN_LATEST_CRASH, + GTK_SORT_DESCENDING); + + gtk_tree_view_set_model(GTK_TREE_VIEW(s_treeview), GTK_TREE_MODEL(s_dumps_list_store)); + + /* buttons are homogenous so set size only for one button and it will + * work for the rest buttons in same gtk_hbox_new() */ + GtkWidget *btn_report = gtk_button_new_from_stock(GTK_STOCK_OPEN); + gtk_widget_set_size_request(btn_report, 200, 30); + + GtkWidget *btn_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE); + + GtkWidget *hbox_report_delete = gtk_hbox_new(true, 4); + gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_delete, true, true, 0); + gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_report, true, true, 0); + + GtkWidget *halign = gtk_alignment_new(1, 0, 0, 0); + gtk_container_add(GTK_CONTAINER(halign), hbox_report_delete); + + GtkWidget *hbox_help_close = gtk_hbutton_box_new(); + GtkWidget *btn_online_help = gtk_button_new_with_mnemonic(_("Online _Help")); + GtkWidget *btn_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_end(GTK_BOX(hbox_help_close), btn_online_help, false, false, 0); + gtk_box_pack_end(GTK_BOX(hbox_help_close), btn_close, false, false, 0); + + gtk_box_pack_start(GTK_BOX(main_vbox), halign, false, false, 10); + gtk_box_pack_start(GTK_BOX(main_vbox), hbox_help_close, false, false, 10); + + /* Double click/Enter handler */ + g_signal_connect(s_treeview, "row-activated", G_CALLBACK(on_row_activated_cb), NULL); + g_signal_connect(btn_report, "clicked", G_CALLBACK(on_btn_report_cb), NULL); + /* Delete handler */ + g_signal_connect(s_treeview, "key-press-event", G_CALLBACK(on_key_press_event_cb), NULL); + g_signal_connect(btn_delete, "clicked", G_CALLBACK(on_btn_delete_cb), NULL); + /* Quit when user closes the main window */ + g_signal_connect(g_main_window, "destroy", gtk_main_quit, NULL); + /* Quit when user click on Cancel button */ + g_signal_connect(btn_close, "clicked", gtk_main_quit, NULL); + /* Show online help */ + g_signal_connect(btn_online_help, "clicked", G_CALLBACK(on_btn_online_help_cb), NULL); + + return g_main_window; +} + + static int inotify_fd = -1; static GIOChannel *channel_inotify; static int channel_inotify_event_id = -1; @@ -182,7 +692,7 @@ static void scan_directory_and_add_to_dirlist(const char *path) } } -void scan_dirs_and_add_to_dirlist(void) +static void scan_dirs_and_add_to_dirlist(void) { char **argv = s_dirs; while (*argv) -- cgit