/*------------------------------------------------------------------------- * Copyright (c) 1999-2005 Kenneth W. Sodemann (stuffle@mac.com) *------------------------------------------------------------------------- * mainwin * * Synopsis: * Create and manipulate the main window for the application. * * $Id: mainwin.c,v 1.112 2005/05/11 00:39:55 stuffle Exp $ * * 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 * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * *------------------------------------------------------------------------- */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "about_dlg.h" #include "archive_dlg.h" #include "attrib_dlg.h" #include "db_utils.h" #include "defs.h" #include "error_chks.h" #include "find_dlg.h" #include "gtkutils.h" #include "login_dlg.h" #include "pr_query.h" #include "person_dlg.h" #include "prepsmain.h" #include "print_dlg.h" #include "prj_rpt_dlg.h" #include "probupdate_dlg.h" #include "project_dlg.h" #include "props.h" #include "query_dlg.h" #include "sqlstr.h" #include "util.h" /* * Define the names of the significant widgets */ #define MAIN_WIN "main_win" #define PROJECT_MENU "project_menu" #define QUERY_MENU "query_menu" #define RESULTS_LIST_VIEW "results_list_view" #define APPBAR "appbar" #define DISPLAY_ARCH_CB "display_arch_cb" #define PK_ARRAY "pk_array" #define COLUMN_NUMBER "column_number" #define NELS "number_of_elements" #define COL_ALREADY_EXISTS -2 #define REFRESH_TIME_NOTIFY "refresh_time_notify" #define ASSIGNEE_COL_NOTIFY "assignee_col_notify" #define PROBLEM_TYPE_COL_NOTIFY "problem_type_col_notify" #define PROJECT_COL_NOTIFY "project_col_notify" #define TITLE_COL_NOTIFY "title_col_notify" #define PR_NUM_COL_NOTIFY "pr_num_col_notify" #define SEVERITY_COL_NOTIFY "severity_col_notify" #define STATUS_COL_NOTIFY "status_col_notify" #define DATE_COL_NOTIFY "date_col_notify" #define SUBMITTER_COL_NOTIFY "submitter_col_notify" #define INACTIVE_PRJ_NOTIFY "inactive_prj_notify" #define ARCH_COL_NOTIFY "arch_col_notify" #define DISP_ARCH_NOTIFY "disp_arch_notify" #define ARCH_MENU_ITEM "arch_menu_item" #define TIMEOUT "timeout" #define REFRESH_TICKS "refresh_ticks" #define REFRESH_COUNTER "counter" #define TICKS_PER_MIN 4 #define PERIOD_IN_MS (60 / (TICKS_PER_MIN)) * 1000 #define SORT_COLUMN "sort_column" #define SORT_ORDER "sort_order" #define PREV_SEL "prev_selection" /* * Status bar strings. */ #define DEFAULT_STAT_STRING _("Connected to database: %s") #define NEW_STRING _("Submit a new problem report") #define EDIT_STRING _("Edit the currently selected problem report") #define FIND_STRING _("Find specific problem reports") #define PRINT_STRING _("Print problem reports") #define EXIT_STRING _("Exit PRepS") #define USER_QUERY_STRING _("Create, edit, and delete user defined display filters") #define SYS_QUERY_STRING _("Create, edit, and delete system wide display filters") #define PROJECTS_STRING _("Manage the projects in this database") #define USERS_STRING _("Manage the users having access to this database") #define ATTRIBUTES_STRING _("Manage the defined severities, statuses, and \ problem types") #define REFRESH_STRING _("Re-execute the current query") #define STAT_RPT_STRING _("Generate the \"Problem Reports by Status\" \ Report") #define VER_RPT_STRING _("Generate the \"Problem Reports by Project Version\" Report") #define CHANGE_LOG_STRING _("Generate the \"Project ChangeLog\" Report") #define NO_SUBMITTER_ACCESS_MSG _("You do not have submitter access to any \ projects.\nPlease see your PRepS administrator or project leader.") #define SYS_FLAG_POS 2 #define PR_QUERY_QUERY "\ SELECT query_num, name, is_system_query \ FROM pr_query \ WHERE is_system_query = TRUE \ OR creator = getpgusername () \ ORDER BY is_system_query, order_num, name" #define PROJECT_LDR "\ SELECT project_num \ FROM project \ WHERE login_id = getpgusername()" #define DEF_WIDTH 550 #define DEF_HEIGHT 325 enum { PROJECT_NAME = 0, PROJECT_PK, NUM_PROJECT_COLS }; /* * NOTE: due to the way that find_col_insert_pos() works, this enumeration * also defines the order in which the columns will be displayed in * the list view. */ enum { RESULT_PR_NUM = 0, RESULT_PROJECT, RESULT_STATUS, RESULT_PROBLEM_TYPE, RESULT_SEVERITY, RESULT_ASSIGNEE, RESULT_SUBMITTER, RESULT_DATE, RESULT_TITLE, RESULT_ARCH, RESULT_PK, /* Start non-displaying columns */ RESULT_ARCH_EDITABLE, NUM_RESULT_COLS }; const gchar *col_titles[] = {N_("PR#"), N_("Project"), N_("Status"), N_("Problem Type"), N_("Severity"), N_("Assignee"), N_("Submitter"), N_("Submission Date"), N_("Title"), N_("Archived")}; /* * prototypes */ static void on_arch_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data); static void on_query_changed (GtkWidget *widget, gpointer user_data); static void on_project_changed (GtkWidget *widget, gpointer user_data); static void on_sort_changed (GtkWidget *widget, gpointer user_data); static void set_sort_order (GtkTreeSortable *ts, GConfClient *client); const gchar *pr_dlg_list = "PR_DLG_LIST"; /* * Returns the position within the columned list that this column should * be added. * * Returns COL_ALREADY_EXISTS if the column is already displayed. */ static gint find_col_insert_pos (GtkTreeView *tree, gint colnum) { GList *col_list; GList *list_iter; gint pos = 0; gint curr_col; g_assert (tree != NULL); col_list = gtk_tree_view_get_columns (tree); for (list_iter = g_list_first (col_list); list_iter != NULL; list_iter = list_iter->next) { curr_col = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (list_iter->data), COLUMN_NUMBER)); if (curr_col == colnum) { return COL_ALREADY_EXISTS; } if (curr_col > colnum) { break; } pos++; } return pos; } static void add_results_column (GtkTreeView *tree, gint colnum, GtkWidget *parent) { GtkCellRenderer *rend; GtkTreeViewColumn *col; gint pos; g_assert (tree != NULL); g_assert (parent != NULL); pos = find_col_insert_pos (tree, colnum); if (pos != COL_ALREADY_EXISTS) { switch (colnum) { case RESULT_ARCH: rend = gtk_cell_renderer_toggle_new (); col = gtk_tree_view_column_new_with_attributes (col_titles[colnum], rend, "active", colnum, NULL); g_signal_connect (rend, "toggled", G_CALLBACK (on_arch_toggled), parent); break; default: rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (col_titles[colnum], rend, "text", colnum, NULL); break; } g_object_set_data (G_OBJECT (col), COLUMN_NUMBER, GINT_TO_POINTER (colnum)); gtk_tree_view_insert_column (tree, col, pos); gtk_tree_view_column_set_sort_column_id (col, colnum); } } static void remove_results_column (GtkTreeView *tree, gint colnum, GtkWidget *parent) { GList *col_list; GList *list_iter; g_assert (tree != NULL); g_assert (parent != NULL); col_list = gtk_tree_view_get_columns (tree); for (list_iter = g_list_first (col_list); list_iter != NULL; list_iter = list_iter->next) { if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (list_iter->data), COLUMN_NUMBER)) == colnum) { gtk_tree_view_remove_column (tree, GTK_TREE_VIEW_COLUMN (list_iter->data)); break; } } } static gint lookup_column_num (const gchar *key) { g_assert (key != NULL); if (strcmp (key, ASSIGNEE_STR) == 0) return RESULT_ASSIGNEE; if (strcmp (key, PROBLEM_TYPE_STR) == 0) return RESULT_PROBLEM_TYPE; if (strcmp (key, PRJ_NAME_STR) == 0) return RESULT_PROJECT; if (strcmp (key, PR_DESCR_STR) == 0) return RESULT_TITLE; if (strcmp (key, PR_RPT_NUM_STR) == 0) return RESULT_PR_NUM; if (strcmp (key, SEVERITY_STR) == 0) return RESULT_SEVERITY; if (strcmp (key, STATUS_STR) == 0) return RESULT_STATUS; if (strcmp (key, SUBMISSION_DT_STR) == 0) return RESULT_DATE; if (strcmp (key, SUBMITTER_STR) == 0) return RESULT_SUBMITTER; if (strcmp (key, ARCH_STR) == 0) return RESULT_ARCH; g_assert_not_reached (); return -1; } static GtkTreeView * create_results_tree_view (GtkTreeModel *model, GtkWidget *main_win) { GtkTreeView *tree; GConfClient *client; gboolean show_assignee; gboolean show_problem_type; gboolean show_prj_name; gboolean show_pr_descr; gboolean show_pr_num; gboolean show_severity; gboolean show_status; gboolean show_submission_date; gboolean show_submitter; gboolean show_arch; gboolean initial_sort = TRUE; g_assert (model != NULL); g_assert (main_win != NULL); client = g_object_get_data (G_OBJECT (main_win), MY_GCONF_CLIENT); g_assert (client != NULL); show_pr_num = display_column_in_results (client, PR_RPT_NUM_COL); show_prj_name = display_column_in_results (client, PRJ_NAME_COL); show_pr_descr = display_column_in_results (client, PR_DESCR_COL); show_severity = display_column_in_results (client, SEVERITY_COL); show_status = display_column_in_results (client, STATUS_COL); show_problem_type = display_column_in_results (client, PROBLEM_TYPE_COL); show_submission_date = display_column_in_results (client, SUBMISSION_DATE_COL); show_submitter = display_column_in_results (client, SUBMITTER_COL); show_assignee = display_column_in_results (client, ASSIGNEE_COL); show_arch = display_column_in_results (client, ARCH_COL); tree = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model)); if (show_pr_num) { add_results_column (tree, RESULT_PR_NUM, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_PR_NUM, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_prj_name) { add_results_column (tree, RESULT_PROJECT, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_PROJECT, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_status) { add_results_column (tree, RESULT_STATUS, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_STATUS, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_arch) { add_results_column (tree, RESULT_ARCH, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_ARCH, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_problem_type) { add_results_column (tree, RESULT_PROBLEM_TYPE, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_PROBLEM_TYPE, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_severity) { add_results_column (tree, RESULT_SEVERITY, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_SEVERITY, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_assignee) { add_results_column (tree, RESULT_ASSIGNEE, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_ASSIGNEE, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_submitter) { add_results_column (tree, RESULT_SUBMITTER, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_SUBMITTER, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_submission_date) { add_results_column (tree, RESULT_DATE, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_DATE, GTK_SORT_ASCENDING); initial_sort = FALSE; } } if (show_pr_descr) { add_results_column (tree, RESULT_TITLE, main_win); if (initial_sort) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), RESULT_TITLE, GTK_SORT_ASCENDING); initial_sort = FALSE; } } return tree; } static gboolean dirty_children (GtkWidget *main_win) { GList *list; gboolean dirty = FALSE; g_assert (main_win != NULL); list = g_object_get_data (G_OBJECT (main_win), pr_dlg_list); list = g_list_first (list); while (list != NULL) { if (problem_update_dlg_dirty (GTK_WIDGET (list->data))) { return TRUE; } list = list->next; } dirty = attrib_dlg_dirty(); dirty = dirty || person_dlg_dirty(); dirty = dirty || project_dlg_dirty(); dirty = dirty || query_dlg_dirty(); return dirty; } /* * The user can exit several ways. This function centralizes the * clean up. Be sure to call it from each signal handler that is * taking care of an exit request. */ static void cleanup_and_quit (GtkWidget *main_win) { GList *temp_list; GList *list_iter; GtkWidget *opt; PGconn *conn; gint timer; GString *cfg; gint x; gint y; GArray *pks; GConfClient *client; guint notify_id; g_assert (main_win != NULL); client = g_object_get_data (G_OBJECT (main_win), MY_GCONF_CLIENT); g_assert (client != NULL); notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), REFRESH_TIME_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), INACTIVE_PRJ_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), ASSIGNEE_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), PROBLEM_TYPE_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), PROJECT_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), TITLE_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), PR_NUM_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), SEVERITY_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), STATUS_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), DATE_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), SUBMITTER_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), ARCH_COL_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } notify_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (main_win), DISP_ARCH_NOTIFY)); if (notify_id != 0) { gconf_client_notify_remove (client, notify_id); } cfg = g_string_new (""); if (GDK_IS_WINDOW (main_win->window)) { gdk_window_get_position (main_win->window, &x, &y); g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, X_POS); gconf_client_set_int (client, cfg->str, x, NULL); g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, Y_POS); gconf_client_set_int (client, cfg->str, y, NULL); } if (GDK_IS_DRAWABLE (main_win->window)) { gdk_drawable_get_size (GDK_DRAWABLE (main_win->window), &x, &y); g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, X_SIZE); gconf_client_set_int (client, cfg->str, x, NULL); g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, Y_SIZE); gconf_client_set_int (client, cfg->str, y, NULL); } timer = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_win), TIMEOUT)); g_source_remove (timer); opt = lookup_widget (main_win, QUERY_MENU); g_assert (opt != NULL); pks = g_object_get_data (G_OBJECT (opt), PK_ARRAY); if (pks != NULL) { g_array_free (pks, TRUE); } temp_list = g_object_get_data (G_OBJECT (main_win), pr_dlg_list); if (temp_list) { list_iter = g_list_first (temp_list); while (list_iter) { g_signal_handlers_block_by_func (list_iter->data, G_CALLBACK (child_dead), (gpointer)pr_dlg_list); gtk_widget_destroy (GTK_WIDGET (list_iter->data)); list_iter = list_iter->next; } g_object_set_data (G_OBJECT (main_win), pr_dlg_list, NULL); g_list_free (temp_list); } conn = (PGconn *)g_object_get_data (G_OBJECT (main_win), MY_DB_CONN); if (conn != NULL) { db_shutdown (conn); } g_string_free (cfg, TRUE); gtk_main_quit (); } /* * read_query_data * * Read the query data from the database so we can put it * in our query list. */ static PGresult * read_query_data (PGconn *conn) { GString *buffer; PGresult *res; g_assert (conn != NULL); buffer = g_string_new (PR_QUERY_QUERY); res = PQexec (conn, buffer->str); g_string_free (buffer, TRUE); return res; } static void draw_pr_list (GtkWidget *parent, PGconn *conn) { GConfClient *client; GtkTreeView *res_tree; #ifdef USE_NEW_GTK GtkComboBox *prj_menu; GtkComboBox *query_menu; #else GtkOptionMenu *prj_menu; GtkOptionMenu *query_menu; #endif GtkToggleButton *arch_cb; GtkListStore *old_store; GtkListStore *new_store; GtkTreeIter iter; gint sel; pr_query_struct *q; GString *sql_buffer; PGresult *res; gint n; gint i; gint pk; GArray *pks; GdkCursor *cursor; GtkSortType order; gint col; gboolean archived; gboolean editable; g_assert (parent != NULL); g_assert (conn != NULL); cursor = gdk_cursor_new (GDK_WATCH); gdk_window_set_cursor (parent->window, cursor); gdk_cursor_unref (cursor); while (gtk_events_pending()) { gtk_main_iteration(); } /* * Get the widgets that we will need information from to build * the query, as well as the widget that will display the results. */ res_tree = GTK_TREE_VIEW (lookup_widget (parent, RESULTS_LIST_VIEW)); #ifdef USE_NEW_GTK prj_menu = GTK_COMBO_BOX (lookup_widget (parent, PROJECT_MENU)); query_menu = GTK_COMBO_BOX (lookup_widget (parent, QUERY_MENU)); #else prj_menu = GTK_OPTION_MENU (lookup_widget (parent, PROJECT_MENU)); query_menu = GTK_OPTION_MENU (lookup_widget (parent, QUERY_MENU)); #endif arch_cb = GTK_TOGGLE_BUTTON (lookup_widget (parent, DISPLAY_ARCH_CB)); g_assert (res_tree != NULL); g_assert (prj_menu != NULL); g_assert (query_menu != NULL); g_assert (arch_cb != NULL); client = g_object_get_data (G_OBJECT (parent), MY_GCONF_CLIENT); g_assert (client != NULL); /* * pks is not asserted, since there may be no queries set up, * in which case pks will be NULL. */ pks = g_object_get_data (G_OBJECT (query_menu), PK_ARRAY); /* * If there is a query selected (which there will be if there are * any queries to select), find out which one it is, and build * the query string. */ #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (query_menu); #else sel = gtk_option_menu_get_history (query_menu); #endif if (pks != NULL && sel != -1) { pk = g_array_index (pks, gint, sel); g_assert (pk != INVALID_PK); q = create_pr_query_from_table (conn, PQuser (conn), pk); } else { q = create_pr_query (PQuser (conn)); } restrict_to_active_projects (q, !show_inactive_projects_in_menu (client)); /* * If any projects from the project list are chosen, add those * limitations to the query. */ #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (prj_menu); #else sel = gtk_option_menu_get_history (prj_menu); #endif if (sel != -1) { pks = g_object_get_data (G_OBJECT (prj_menu), PK_ARRAY); g_assert (pks != NULL); pk = g_array_index (pks, gint, sel); if (pk != INVALID_PK) { add_project_restriction (q, pk); } } /* * Get the query string, and execute the query. */ sql_buffer = create_query_string (q, gtk_toggle_button_get_active (arch_cb)); res = PQexec (conn, sql_buffer->str); if (chk_sql_error (res, "Getting Problem Reports")) { /* * Display the results. */ old_store = GTK_LIST_STORE (gtk_tree_view_get_model (res_tree)); gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (old_store), &col, &order); new_store = gtk_list_store_new (NUM_RESULT_COLS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_BOOLEAN); gtk_list_store_clear (new_store); n = PQntuples (res); for (i = 0; i < n; i++) { pk = atoi (PQgetvalue (res, i, PR_NUMBER_POS)); gtk_list_store_append (new_store, &iter); archived = (toupper(PQgetvalue (res, i, ARCH_POS)[0]) == 'T'); editable = (toupper(PQgetvalue (res, i, EDIT_POS)[0]) == 'T'); gtk_list_store_set (new_store, &iter, RESULT_PR_NUM, pk, RESULT_TITLE, PQgetvalue (res, i, PR_TITLE_POS), RESULT_PROBLEM_TYPE, PQgetvalue (res, i, PROBLEM_TYPE_NAME_POS), RESULT_STATUS, PQgetvalue (res, i, STATUS_NAME_POS), RESULT_SEVERITY, PQgetvalue (res, i, SEVERITY_NAME_POS), RESULT_PROJECT, PQgetvalue (res, i, PROJECT_NAME_POS), RESULT_ASSIGNEE, PQgetvalue (res, i, RESPONSIBLE_POS), RESULT_SUBMITTER, PQgetvalue (res, i, SUBMITTER_POS), RESULT_DATE, PQgetvalue (res, i, CREATION_DATE_POS), RESULT_ARCH, archived, RESULT_ARCH_EDITABLE, editable, RESULT_PK, pk, -1); } gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (new_store), col, order); g_signal_connect (new_store, "sort-column-changed", G_CALLBACK (on_sort_changed), parent); gtk_tree_view_set_model (res_tree, GTK_TREE_MODEL (new_store)); g_object_unref (old_store); } /* * Clean up before we leave. */ PQclear (res); g_string_free (sql_buffer, TRUE); destroy_pr_query (q); /* * If we have a lot of information in the list, it may take a second * or two to draw. Clear the queue of pending items before we return. */ while (gtk_events_pending()) { gtk_main_iteration(); } gdk_window_set_cursor (parent->window, NULL); } static gboolean submitter_access (GtkWidget *parent, PGconn *conn) { PGresult *res; GString *sql; gint n = 0; g_assert (parent != NULL); g_assert (conn != NULL); sql = g_string_new ("select count (*) "); sql = g_string_append (sql, "from submitter s, project p "); sql = g_string_append (sql, "where p.active = TRUE "); sql = g_string_append (sql, "and p.project_num = s.project_num "); sql = g_string_append( sql, "and s.login_id = getpgusername() "); res = PQexec (conn, sql->str); if (chk_sql_error (res, _("Getting submitter access"))) { n = atoi (PQgetvalue (res, 0, 0)); } PQclear (res); g_string_free (sql, TRUE); return (n > 0); } #ifdef USE_NEW_GTK static void draw_project_menu (GtkWidget *parent, PGconn *conn) { GtkComboBox *prj_combo; GArray *pks; GString *sql_buffer; GString *config_str; gint defpk; PGresult *res; gint n; gint i; gint pk; gint sel; gint nels; GConfClient *client; GError *error = NULL; g_assert (parent != NULL); g_assert (conn != NULL); /* * Get pointers to the widgets that we will need. */ prj_combo = GTK_COMBO_BOX (lookup_widget (parent, PROJECT_MENU)); g_assert (prj_combo != NULL); client = g_object_get_data (G_OBJECT (parent), MY_GCONF_CLIENT); g_assert (client != NULL); /* * Build the project query. */ sql_buffer = g_string_new (""); prj_sql_str (sql_buffer, (show_inactive_projects_in_menu (client) ? ALL_ITEMS : ACTIVE_ITEMS_ONLY), TRUE, TRUE, TRUE, FALSE, client, 0); /* * Execute the query, and if all checks out, fill the project * list with the results. */ res = PQexec (conn, sql_buffer->str); if (chk_sql_error (res, "filling project list")) { /* * If there is a old list of project pk's, the combo box also * has some entries that need to be removed. */ pks = g_object_get_data (G_OBJECT (prj_combo), PK_ARRAY); if (pks != NULL) { sel = gtk_combo_box_get_active (prj_combo); defpk = ((sel == -1) ? 0 : (g_array_index (pks, gint, sel))); nels = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (prj_combo), NELS)); for (i = 0; i < nels; i++) { gtk_combo_box_remove_text (prj_combo, nels - i - 1); } g_array_free (pks, TRUE); } else { config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, curr_db_name->str, DEF_PROJECT); defpk = gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; defpk = 0; } g_string_free (config_str, TRUE); } /* * Fill the combo box. Always start with "All Projects". */ n = PQntuples (res); pks = g_array_sized_new (FALSE, FALSE, sizeof (gint), n); gtk_combo_box_append_text (prj_combo, _("All Projects")); pk = INVALID_PK; g_array_append_val (pks, pk); sel = 0; for (i = 0; i < n; i++) { gtk_combo_box_append_text (prj_combo, PQgetvalue (res, i, SQLSTR_NAME_POS)); pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); g_array_append_val (pks, pk); if (pk == defpk) { sel = i + 1; } } g_object_set_data (G_OBJECT (prj_combo), PK_ARRAY, pks); g_object_set_data (G_OBJECT (prj_combo), NELS, GINT_TO_POINTER (n + 1)); gtk_combo_box_set_active (prj_combo, sel); g_object_set_data (G_OBJECT (prj_combo), PREV_SEL, GINT_TO_POINTER (sel)); } PQclear (res); g_string_free (sql_buffer, TRUE); } #else static void draw_project_menu (GtkWidget *parent, PGconn *conn) { GtkOptionMenu *prj_menu; GtkWidget *menu; GtkWidget *item; GArray *pks; GString *sql_buffer; GString *config_str; gint defpk; PGresult *res; gint n; gint i; gint pk; gint sel; GConfClient *client; GError *error = NULL; g_assert (parent != NULL); g_assert (conn != NULL); /* * Get pointers to the widgets that we will need. */ prj_menu = GTK_OPTION_MENU (lookup_widget (parent, PROJECT_MENU)); g_assert (prj_menu != NULL); client = g_object_get_data (G_OBJECT (parent), MY_GCONF_CLIENT); g_assert (client != NULL); /* * Build the project query. */ sql_buffer = g_string_new (""); prj_sql_str (sql_buffer, (show_inactive_projects_in_menu (client) ? ALL_ITEMS : ACTIVE_ITEMS_ONLY), TRUE, TRUE, TRUE, FALSE, client, 0); /* * Execute the query, and if all checks out, fill the project * list with the results. */ res = PQexec (conn, sql_buffer->str); if (chk_sql_error (res, "filling project list")) { /* * If there is a old list of project pk's, the option menu also * has a menu. Destroy both of them... */ pks = g_object_get_data (G_OBJECT (prj_menu), PK_ARRAY); if (pks != NULL) { sel = gtk_option_menu_get_history (prj_menu); defpk = ((sel == -1) ? 0 : (g_array_index (pks, gint, sel))); gtk_option_menu_remove_menu (prj_menu); g_array_free (pks, TRUE); } else { config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, curr_db_name->str, DEF_PROJECT); defpk = gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; defpk = 0; } g_string_free (config_str, TRUE); } /* * Build a new menu. Always start with "All Projects". */ n = PQntuples (res); menu = gtk_menu_new (); pks = g_array_sized_new (FALSE, FALSE, sizeof (gint), n); item = gtk_menu_item_new_with_label (_("All Projects")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); pk = INVALID_PK; g_array_append_val (pks, pk); sel = 0; for (i = 0; i < n; i++) { item = gtk_menu_item_new_with_label (PQgetvalue (res, i, SQLSTR_NAME_POS)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); g_array_append_val (pks, pk); if (pk == defpk) { sel = i + 1; } } g_object_set_data (G_OBJECT (prj_menu), PK_ARRAY, pks); gtk_option_menu_set_menu (prj_menu, menu); gtk_option_menu_set_history (prj_menu, sel); g_object_set_data (G_OBJECT (prj_menu), PREV_SEL, GINT_TO_POINTER (sel)); } PQclear (res); g_string_free (sql_buffer, TRUE); } #endif /* * Fill the combo box with the current user and system queries. * * Attach a list to the combo that contains the PK/name pairs to * make it easy to find the PK when the user picks a query. */ #ifdef USE_NEW_GTK static void draw_query_combo (GtkComboBox *combo, PGconn *conn, GConfClient *client) { GArray *pks; gint i, n; gint nels; gint sel; gint defpk; gint pk; GString *config_str; GError *error = NULL; PGresult *res; g_assert (combo != NULL); g_assert (conn != NULL); g_assert (client != NULL); /* * If we have a previous PK_ARRAY, we also have a combo box where * we need to remove the existing items. When we rebuild the items * in the combo box, we will want to display the same item that was * displayed before the call (if it is still there). * * Otherwise, get the default item from the config files. */ pks = g_object_get_data (G_OBJECT (combo), PK_ARRAY); nels = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), NELS)); if (pks != NULL) { sel = gtk_combo_box_get_active (combo); defpk = ((sel == -1) ? 0 : (g_array_index (pks, gint, sel))); for (i = 0; i < nels; i++) { /* * I am not sure what happens if we remove from the start * of the combo, so I will just keep removing from the end. */ gtk_combo_box_remove_text (combo, nels - i - 1); } g_array_free (pks, TRUE); } else { config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, curr_db_name->str, MAIN_QUERY); defpk = gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; defpk = 0; } g_string_free (config_str, TRUE); } res = read_query_data (conn); if (chk_sql_error (res, "getting PR queries")) { n = PQntuples (res); g_object_set_data (G_OBJECT (combo), NELS, GINT_TO_POINTER (n)); pks = g_array_sized_new (FALSE, FALSE, sizeof (gint), n); sel = 0; for (i = 0; i < n; i++) { gtk_combo_box_append_text (combo, PQgetvalue (res, i, SQLSTR_NAME_POS)); pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); g_array_append_val (pks, pk); if (pk == defpk) { sel = i; } } g_object_set_data (G_OBJECT (combo), PK_ARRAY, pks); gtk_combo_box_set_active (combo, sel); g_object_set_data (G_OBJECT (combo), PREV_SEL, GINT_TO_POINTER (sel)); } PQclear (res); } #else static void draw_query_combo (GtkOptionMenu *opt, PGconn *conn, GConfClient *client) { PGresult *res; gint i, n; gint sel; GtkWidget *menu; GtkWidget *item; GArray *pks; gint defpk; gint pk; GString *config_str; GError *error = NULL; g_assert (opt != NULL); g_assert (conn != NULL); g_assert (client != NULL); /* * If we have a previous PK_ARRAY, we also have a previous menu that * needs to be destroyed, etc. When we rebuild the menu, we will * want to display the same item (if it is still there). * * Otherwise, get the default item from the config files. */ pks = g_object_get_data (G_OBJECT (opt), PK_ARRAY); if (pks != NULL) { sel = gtk_option_menu_get_history (opt); defpk = ((sel == -1) ? 0 : (g_array_index (pks, gint, sel))); gtk_option_menu_remove_menu (opt); g_array_free (pks, TRUE); } else { config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, curr_db_name->str, MAIN_QUERY); defpk = gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; defpk = 0; } g_string_free (config_str, TRUE); } res = read_query_data (conn); if (chk_sql_error (res, "getting PR queries")) { n = PQntuples (res); menu = gtk_menu_new (); pks = g_array_sized_new (FALSE, FALSE, sizeof (gint), n); sel = 0; for (i = 0; i < n; i++) { item = gtk_menu_item_new_with_label (PQgetvalue (res, i, SQLSTR_NAME_POS)); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); g_array_append_val (pks, pk); if (pk == defpk) { sel = i; } } g_object_set_data (G_OBJECT (opt), PK_ARRAY, pks); gtk_option_menu_set_menu (opt, menu); gtk_option_menu_set_history (opt, sel); g_object_set_data (G_OBJECT (opt), PREV_SEL, GINT_TO_POINTER (sel)); } PQclear (res); } #endif void refresh_query_combo (GtkWidget *main_win) { #ifdef USE_NEW_GTK GtkComboBox *query_menu; #else GtkOptionMenu *query_menu; #endif PGconn *conn; GConfClient *client; g_assert (main_win != NULL); #ifdef USE_NEW_GTK query_menu = GTK_COMBO_BOX (lookup_widget (main_win, QUERY_MENU)); #else query_menu = GTK_OPTION_MENU (lookup_widget (main_win, QUERY_MENU)); #endif g_assert (query_menu != NULL); conn = g_object_get_data (G_OBJECT (main_win), MY_DB_CONN); g_assert (conn != NULL); client = g_object_get_data (G_OBJECT (main_win), MY_GCONF_CLIENT); g_assert (client != NULL); draw_query_combo (query_menu, conn, client); } static void set_auto_refresh_time (GtkWidget *main_win) { GConfClient *client; gint target; g_assert (main_win != NULL); client = g_object_get_data (G_OBJECT (main_win), MY_GCONF_CLIENT); g_assert (client != NULL); target = auto_refresh_rate (client) * TICKS_PER_MIN; g_object_set_data (G_OBJECT (main_win), REFRESH_TICKS, GINT_TO_POINTER (target)); } static void set_sort_order (GtkTreeSortable *ts, GConfClient *client) { GString *config_str; gint col; GtkSortType order; GError *error = NULL; g_assert (ts != NULL); g_assert (client != NULL); config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SORT_COLUMN); col = gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; col = 0; } g_string_printf (config_str, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SORT_ORDER); order = (GtkSortType)gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; order = 0; } gtk_tree_sortable_set_sort_column_id (ts, col, order); g_string_free (config_str, TRUE); } static void show_arch_change_notify (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data) { gboolean display_arch; GConfValue *value; GtkToggleButton *arch_cb; g_assert (client != NULL); g_assert (entry != NULL); g_assert (user_data != NULL); arch_cb = GTK_TOGGLE_BUTTON (lookup_widget (user_data, DISPLAY_ARCH_CB)); g_assert (arch_cb != NULL); value = gconf_entry_get_value (entry); if (value != NULL && value->type == GCONF_VALUE_BOOL) { display_arch = gconf_value_get_bool (value); } else { display_arch = FALSE; } /* * Setting the toggle button will emit a toggle signal, which in * turn will end up setting the show arch value in GConf, which will * get us back into this handler function. To avoid the obvious * infinite loop this would produce, only actually change the * check box values if we need to . */ if (gtk_toggle_button_get_active (arch_cb) != display_arch) { gtk_toggle_button_set_active (arch_cb, display_arch); } } static void display_col_change_notify (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data) { GConfValue *value; GtkTreeView *tree; gboolean display; const gchar *fullkey; gchar *key; gint colnum; g_assert (client != NULL); g_assert (entry != NULL); g_assert (user_data != NULL); value = gconf_entry_get_value (entry); if (value != NULL && value->type == GCONF_VALUE_BOOL) { display = gconf_value_get_bool (value); } else { display = FALSE; } fullkey = gconf_entry_get_key (entry); key = strrchr (fullkey, '/') + 1; colnum = lookup_column_num (key); tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET (user_data), RESULTS_LIST_VIEW)); g_assert (tree != NULL); if (display) { add_results_column (tree, colnum, GTK_WIDGET (user_data)); } else { remove_results_column (tree, colnum, GTK_WIDGET (user_data)); } } static void refresh_time_change_notify (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data) { GConfValue *value; gint target; g_assert (client != NULL); g_assert (entry != NULL); g_assert (user_data != NULL); value = gconf_entry_get_value (entry); if (value != NULL && value->type == GCONF_VALUE_INT) { target = gconf_value_get_int (value) * TICKS_PER_MIN; } else { target = 0; } g_object_set_data (G_OBJECT (user_data), REFRESH_TICKS, GINT_TO_POINTER (target)); } static void inactive_prj_change_notify (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data) { PGconn *conn; g_assert (client != NULL); g_assert (entry != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); draw_project_menu (GTK_WIDGET (user_data), conn); draw_pr_list (GTK_WIDGET (user_data), conn); } static void setup_gconf_notify_handlers (GConfClient *client, GtkWidget *main_win) { GString *key; guint notify_id; g_assert (client != NULL); g_assert (main_win != NULL); key = g_string_new (BASE_KEY); g_string_append_printf (key, "/%s/%s", GENERAL_SECTION, AUTO_REF_RATE); notify_id = gconf_client_notify_add (client, key->str, refresh_time_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), REFRESH_TIME_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, INACTIVE_PRJ_STR); notify_id = gconf_client_notify_add (client, key->str, inactive_prj_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), INACTIVE_PRJ_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, ASSIGNEE_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), ASSIGNEE_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, PROBLEM_TYPE_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), PROBLEM_TYPE_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, PRJ_NAME_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), PROJECT_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, PR_DESCR_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), TITLE_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, PR_RPT_NUM_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), PR_NUM_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SEVERITY_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), SEVERITY_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, STATUS_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), STATUS_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SUBMISSION_DT_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), DATE_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SUBMITTER_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), SUBMITTER_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, ARCH_STR); notify_id = gconf_client_notify_add (client, key->str, display_col_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), ARCH_COL_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_printf (key, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, SHOW_ARCH); notify_id = gconf_client_notify_add (client, key->str, show_arch_change_notify, main_win, NULL, NULL); g_object_set_data (G_OBJECT (main_win), DISP_ARCH_NOTIFY, GUINT_TO_POINTER (notify_id)); g_string_free (key, TRUE); } static gint periodic_processing (gpointer main_win) { gint refresh_count; gint refresh_target; PGconn *conn; g_assert (main_win != NULL); refresh_target = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_win), REFRESH_TICKS)); if (refresh_target > 0) { refresh_count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_win), REFRESH_COUNTER)) + 1; if (refresh_count >= refresh_target) { refresh_count = 0; conn = g_object_get_data (G_OBJECT (main_win), MY_DB_CONN); draw_pr_list (GTK_WIDGET (main_win), conn); } g_object_set_data (G_OBJECT (main_win), REFRESH_COUNTER, GINT_TO_POINTER (refresh_count)); } return TRUE; } static void on_arch_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data) { GtkTreeView *tree; GtkListStore *store; GtkTreeIter iter; GtkTreePath *path = gtk_tree_path_new_from_string (path_str); gboolean archived; PGconn *conn; gint pk; gboolean editable; g_assert (cell != NULL); g_assert (path_str != NULL); g_assert (data != NULL); tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET (data), RESULTS_LIST_VIEW)); g_assert (tree != NULL); store = GTK_LIST_STORE (gtk_tree_view_get_model (tree)); conn = g_object_get_data (G_OBJECT (data), MY_DB_CONN); g_assert (conn != NULL); gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, RESULT_PK, &pk, RESULT_ARCH, &archived, RESULT_ARCH_EDITABLE, &editable, -1); if (editable) { archived = (archived) ? FALSE : TRUE; gtk_list_store_set (store, &iter, RESULT_ARCH, archived, -1); set_problem_report_archived (conn, pk, archived); } } static void on_display_arch_toggled (GtkWidget *widget, gpointer user_data) { GConfClient *client; gboolean value; GString *key; PGconn *conn; g_assert (widget != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); client = g_object_get_data (G_OBJECT (user_data), MY_GCONF_CLIENT); g_assert (client != NULL); key = g_string_new (""); g_string_printf (key, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, SHOW_ARCH); value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); gconf_client_set_bool (client, key->str, value, NULL); draw_pr_list (GTK_WIDGET (user_data), conn); g_string_free (key, TRUE); } /* * on_main_win_show * * Things that need to be done when we first show the main * window: * o Get the list of valid projects for the current * user. This is defined as the projects where the * user is on the submitter list, the responsible list, * or is the project leader. */ static void on_main_win_show (GtkWidget *widget, gpointer user_data) { PGconn *conn; #ifdef USE_NEW_GTK GtkComboBox *query_menu; #else GtkOptionMenu *query_menu; #endif GtkWidget *prj_menu; gint timer; GConfClient *client; GtkWidget *arch_cb; GString *key; GError *error = NULL; gboolean flag; g_assert (widget != NULL); conn = g_object_get_data (G_OBJECT (widget), MY_DB_CONN); g_assert (conn != NULL); client = g_object_get_data (G_OBJECT (widget), MY_GCONF_CLIENT); g_assert (client != NULL); arch_cb = lookup_widget (widget, DISPLAY_ARCH_CB); g_assert (client != NULL); timer = g_timeout_add (PERIOD_IN_MS, periodic_processing, widget); g_object_set_data (G_OBJECT (widget), TIMEOUT, GINT_TO_POINTER (timer)); set_auto_refresh_time (widget); /* * Set the query displayed in the query combo based on the INI file. * This will normally be the last one that the user had selected * last time preps was just down. */ #ifdef USE_NEW_GTK query_menu = GTK_COMBO_BOX (lookup_widget (widget, QUERY_MENU)); #else query_menu = GTK_OPTION_MENU (lookup_widget (widget, QUERY_MENU)); #endif g_assert (query_menu != NULL); draw_query_combo (query_menu, conn, client); /* * This MUST be before the draw_pr_list() call. */ key = g_string_new (""); g_string_printf (key, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, SHOW_ARCH); flag = gconf_client_get_bool (client, key->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; flag = FALSE; } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (arch_cb), flag); draw_project_menu (widget, conn); draw_pr_list (widget, conn); /* * Now that everything is drawn, attach some of the handlers that * handle changes... */ prj_menu = lookup_widget (widget, PROJECT_MENU); g_assert (prj_menu != NULL); g_signal_connect (query_menu, "changed", G_CALLBACK (on_query_changed), widget); g_signal_connect (prj_menu, "changed", G_CALLBACK (on_project_changed), widget); g_signal_connect (arch_cb, "toggled", G_CALLBACK (on_display_arch_toggled), widget); g_string_free (key, TRUE); } void refresh_project_list (gpointer data) { PGconn *conn; g_assert (data != NULL); conn = g_object_get_data (G_OBJECT (data), MY_DB_CONN); g_assert (conn != NULL); draw_project_menu (GTK_WIDGET (data), conn); } void refresh_pr_list (gpointer data) { PGconn *conn; g_assert (data != NULL); conn = g_object_get_data (G_OBJECT (data), MY_DB_CONN); g_assert (conn != NULL); draw_pr_list (GTK_WIDGET (data), conn); } static void refresh_menu_access (GtkWidget *main_win) { gboolean admin = FALSE; gboolean prjldr = FALSE; GtkWidget *menu_item; menu_item = lookup_widget (main_win, ARCH_MENU_ITEM); g_assert (menu_item != NULL); admin = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_win), ADMIN_USER)) == 1); /* * If the dude is an admin, there is no reason to do this other * junk. If the logic that sets the item sensitive is ever changed, * that may no longer be the case, but for now, lets just save * a step. */ if (!admin) { PGconn *conn; PGresult *res; conn = g_object_get_data (G_OBJECT (main_win), MY_DB_CONN); g_assert (conn != NULL); res = PQexec (conn, PROJECT_LDR); if (chk_sql_error (res, "Get project user leads")) { prjldr = (PQntuples (res) > 0); } PQclear (res); } gtk_widget_set_sensitive (menu_item, admin || prjldr); } static void raise_or_create_pr_update_dlg (GtkWidget *main_win, PGconn *conn, gint pk_num) { GtkWidget *dlg; GList *child_list; GList *list_iter; g_assert (main_win != NULL); g_assert (conn != NULL); /* * Go through the existing list of children first. If we have a * child that already uses this PK, just bring that one to the * front. */ child_list = g_object_get_data (G_OBJECT (main_win), pr_dlg_list); list_iter = g_list_first (child_list); while (list_iter) { /* * If we find a child displaying the same PK, just raise it and * return. */ if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (list_iter->data), PK_NUM)) == pk_num) { gdk_window_show (GTK_WIDGET (list_iter->data)->window); gdk_window_raise (GTK_WIDGET (list_iter->data)->window); return; } list_iter = list_iter->next; } /* * Didn't find a child already displaying the PR, so create one. */ dlg = create_problem_update_dlg (main_win, conn, pk_num); child_list = g_list_append (child_list, dlg); g_object_set_data (G_OBJECT (main_win), pr_dlg_list, child_list); /* * Register child_dead() to remove the child from the list when it * dies. */ g_signal_connect (dlg, "destroy", G_CALLBACK (child_dead), (gpointer)pr_dlg_list); gtk_widget_show (dlg); return; } /* * Signal handlers for the "Problem Reports" menu. * * New... * Modify... * Find... * --- * Exit */ static void on_new_pr (GtkWidget *widget, gpointer user_data) { GtkWidget *dlg; PGconn *conn; GList *child_list; g_assert (widget != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); if (submitter_access (GTK_WIDGET (user_data), conn)) { dlg = create_problem_update_dlg (GTK_WIDGET (user_data), conn, INVALID_PK); /* * Setup the child_dead() callback so the child is removed from the * child list when the child dies. */ g_signal_connect (dlg, "destroy", G_CALLBACK (child_dead), (gpointer)pr_dlg_list); child_list = g_object_get_data (G_OBJECT (user_data), pr_dlg_list); child_list = g_list_append (child_list, dlg); g_object_set_data (G_OBJECT (user_data), pr_dlg_list, child_list); gtk_widget_show (dlg); } else { dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, NO_SUBMITTER_ACCESS_MSG); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); } return; } static void on_modify (GtkWidget *widget, gpointer user_data) { PGconn *conn; GtkTreeIter iter; GtkTreeView *tree; GtkListStore *store; GtkTreeSelection *sel; gint pk_num; GtkWidget *msg_dlg; g_assert (widget != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET (user_data), RESULTS_LIST_VIEW)); g_assert (tree != NULL); store = GTK_LIST_STORE (gtk_tree_view_get_model (tree)); sel = gtk_tree_view_get_selection (tree); /* * The user must have selected a PR to modify. */ if (!gtk_tree_selection_get_selected (sel, NULL, &iter)) { msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("You must select a problem to modify.")); gtk_dialog_run (GTK_DIALOG (msg_dlg)); gtk_widget_destroy (msg_dlg); return; } gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, RESULT_PK, &pk_num, -1); raise_or_create_pr_update_dlg (GTK_WIDGET (user_data), conn, pk_num); return; } static void on_find (GtkWidget *widget, gpointer user_data) { PGconn *conn; g_assert (widget != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); show_find_dlg (GTK_WIDGET (user_data), conn); } static void on_archive (GtkWidget *widget, gpointer user_data) { PGconn *conn; g_assert (widget != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); show_archive_dlg (GTK_WIDGET (user_data), conn); } static void on_login (GtkWidget *widget, gpointer user_data) { GtkWidget *msg_dlg; DbLoginData db_data; gboolean valid_new_db = FALSE; PGconn *curr_conn; PGconn *conn; GnomeAppBar *appbar; GString *stat_string; GList *temp_list; GList *list_iter; GConfClient *client; g_assert (widget != NULL); g_assert (user_data != NULL); client = g_object_get_data (G_OBJECT (user_data), MY_GCONF_CLIENT); g_assert (client != NULL); /* * Check for dirty children. If there are dirty children, and the * user chooses to cancel, just return without doing anything... */ if (dirty_children (GTK_WIDGET (user_data))) { msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Some items contain unsaved changes.\n" "If you continue, all unsaved changes will be lost.\n" "Do you want to continue?")); if (gtk_dialog_run (GTK_DIALOG (msg_dlg)) == GTK_RESPONSE_NO) { gtk_widget_destroy (msg_dlg); return; } gtk_widget_destroy (msg_dlg); } curr_conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (curr_conn != NULL); init_db_data (client, &db_data); while (!valid_new_db && execute_login_dlg (GTK_WIDGET (user_data), &db_data, client) == GTK_RESPONSE_OK) { conn = db_login (&db_data); if (PQstatus (conn) == CONNECTION_BAD) { syslog (LOG_ERR, "Error loggin on to database: %s", db_data.db_name->str); msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, PQerrorMessage (conn)); gtk_dialog_run (GTK_DIALOG (msg_dlg)); gtk_widget_destroy (msg_dlg); } else { /* * Any child windows we have will be associated with the old * database connection, so close them before shutting down the * old connection. */ temp_list = g_object_get_data (G_OBJECT (user_data), (gpointer)pr_dlg_list); if (temp_list != NULL) { list_iter = g_list_first (temp_list); while (list_iter) { g_signal_handlers_block_by_func (list_iter->data, G_CALLBACK (child_dead), (gpointer)pr_dlg_list); gtk_widget_destroy (GTK_WIDGET (list_iter->data)); list_iter = list_iter->next; } g_list_free (temp_list); g_object_set_data (G_OBJECT (user_data), pr_dlg_list, NULL); } destroy_attrib_dlg(); destroy_find_dlg(); destroy_person_dlg(); destroy_project_dlg(); destroy_query_dlg(); db_shutdown (curr_conn); /* * I am not _really_ sure if we need to remove it, but the * documentation implies that the set will "destroy" the old * data, which we dont _really_ want since we never allocated * anything dealing with the first conn pointer... */ g_object_set_data (G_OBJECT (user_data), MY_DB_CONN, NULL); g_object_set_data (G_OBJECT (user_data), ADMIN_USER, NULL); g_object_set_data (G_OBJECT (user_data), MY_DB_CONN, conn); g_object_set_data (G_OBJECT (user_data), ADMIN_USER, GINT_TO_POINTER (get_db_access_lvl (conn))); valid_new_db = TRUE; refresh_query_combo (GTK_WIDGET (user_data)); refresh_project_list (user_data); refresh_pr_list (user_data); refresh_menu_access (GTK_WIDGET (user_data)); /* * reset the status string and the global name var */ stat_string = g_string_new (""); g_string_printf (stat_string, DEFAULT_STAT_STRING, db_data.db_name->str); curr_db_name = g_string_assign (curr_db_name, db_data.db_name->str); appbar = g_object_get_data (G_OBJECT (user_data), APPBAR); g_assert (appbar != NULL); gnome_appbar_set_default (appbar, stat_string->str); g_string_free (stat_string, TRUE); } } clear_db_data (&db_data); return; } #ifdef PRINTING_SUPPORTED static void append_sel_list (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gint pk; GList **list = data; g_assert (model != NULL); g_assert (path != NULL); g_assert (iter != NULL); g_assert (data != NULL); gtk_tree_model_get (model, iter, RESULT_PK, &pk, -1); *list = g_list_append (*list, GINT_TO_POINTER (pk)); } static void on_print (GtkWidget *widget, gpointer user_data) { GtkTreeView *tree; GtkTreeModel *model; GtkTreeSelection *sel; GtkTreeIter iter; PGconn *conn; GList *main_list = NULL; GList *sel_list = NULL; gint pk_num; GtkWidget *msg_dlg; g_assert (widget != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET (user_data), RESULTS_LIST_VIEW)); model = gtk_tree_view_get_model (tree); /* * Build the main list */ if (gtk_tree_model_get_iter_first (model, &iter)) { do { gtk_tree_model_get (model, &iter, RESULT_PK, &pk_num, -1); main_list = g_list_append (main_list, GINT_TO_POINTER (pk_num)); } while (gtk_tree_model_iter_next (model, &iter)); } /* * If the main_list is NULL, we have nothing that can be printed. Tell * the user such, and go no further. */ if (main_list == NULL) { msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("There is nothing to print.")); gtk_dialog_run (GTK_DIALOG (msg_dlg)); gtk_widget_destroy (msg_dlg); return; } /* * Build the selection list, assume we can have multiple selections * whether or not we actually can. */ sel = gtk_tree_view_get_selection (tree); gtk_tree_selection_selected_foreach (sel, append_sel_list, &sel_list); execute_print_dlg (GTK_WIDGET (user_data), conn, main_list, sel_list); g_list_free (main_list); g_list_free (sel_list); } #endif static void on_Exit_activate (GtkMenuItem *menuitem, gpointer user_data) { GtkWidget *msg_dlg; g_assert (menuitem != NULL); g_assert (user_data != NULL); if (dirty_children (GTK_WIDGET (user_data))) { msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Some items contain unsaved changes.\n" "If you exit, all unsaved changes will be lost.\n" "Do you want to exit?")); if (gtk_dialog_run (GTK_DIALOG (msg_dlg)) == GTK_RESPONSE_NO) { gtk_widget_destroy (msg_dlg); return; } gtk_widget_destroy (msg_dlg); } cleanup_and_quit (GTK_WIDGET (user_data)); } /* * Signal handlers for the "Queries" menu. * * User... * System... */ static void on_User_query_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; gboolean admin_user; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); admin_user = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (user_data), ADMIN_USER)) == 1); show_query_dlg (GTK_WIDGET (user_data), conn, FALSE, admin_user); } static void on_System_query_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; gboolean admin_user; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); admin_user = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (user_data), ADMIN_USER)) == 1); show_query_dlg (GTK_WIDGET (user_data), conn, TRUE, admin_user); } /* * Signal handlers for the "System" menu. * * Projects... * Users... * Attributes... */ static void on_Projects_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; gboolean admin_user; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); admin_user = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (user_data), ADMIN_USER)) == 1); show_project_dlg (GTK_WIDGET (user_data), conn, admin_user); return; } static void on_Users_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; gboolean admin_user; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); admin_user = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (user_data), ADMIN_USER)) == 1); show_person_dlg (GTK_WIDGET (user_data), conn, admin_user); return; } static void on_Attributes_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; gboolean admin_user; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn); admin_user = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (user_data), ADMIN_USER)) == 1); show_attrib_dlg (GTK_WIDGET (user_data), conn, admin_user); return; } static void on_Properties_activate (GtkMenuItem *menuitem, gpointer user_data) { g_assert (menuitem != NULL); g_assert (user_data != NULL); show_prop_dlg (user_data); return; } static void on_StatusRpt_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn); execute_prj_rpt_dlg (user_data, conn, StatusRpt); return; } static void on_VerRpt_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn); execute_prj_rpt_dlg (user_data, conn, VersionRpt); return; } static void on_ChangeLog_activate (GtkMenuItem *menuitem, gpointer user_data) { PGconn *conn; g_assert (menuitem != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn); execute_prj_rpt_dlg (user_data, conn, ChangeLog); return; } /* * Signal handlers for the "Help" menu. * * About... */ static void on_About_activate (GtkMenuItem *menuitem, gpointer user_data) { g_assert (menuitem != NULL); g_assert (user_data != NULL); show_about_dlg (GTK_WIDGET (user_data)); return; } static void on_refresh_button_clicked (GtkButton *button, gpointer user_data) { PGconn *conn; g_assert (button != NULL); g_assert (user_data != NULL); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); draw_pr_list (GTK_WIDGET (user_data), conn); } static void on_exit_button_clicked (GtkButton *button, gpointer user_data) { GtkWidget *msg_dlg; g_assert (button != NULL); g_assert (user_data != NULL); if (dirty_children (GTK_WIDGET (user_data))) { msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Some items contain unsaved changes.\n" "If you exit, all unsaved changes will be lost.\n" "Do you want to exit?")); if (gtk_dialog_run (GTK_DIALOG (msg_dlg)) == GTK_RESPONSE_NO) { gtk_widget_destroy (msg_dlg); return; } gtk_widget_destroy (msg_dlg); } cleanup_and_quit (GTK_WIDGET (user_data)); } static gboolean on_main_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { g_assert (widget != NULL); g_assert (event != NULL); return FALSE; } static void on_main_destroy (GObject *object, gpointer user_data) { g_assert (object != NULL); cleanup_and_quit (GTK_WIDGET (object)); } static void on_sort_changed (GtkWidget *widget, gpointer user_data) { GtkSortType order; gint col; GConfClient *client; GString *config_str; g_assert (widget != NULL); g_assert (user_data != NULL); client = g_object_get_data (G_OBJECT (user_data), MY_GCONF_CLIENT); g_assert (client != NULL); config_str = g_string_new (""); gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (widget), &col, &order); g_string_printf (config_str, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SORT_COLUMN); gconf_client_set_int (client, config_str->str, col, NULL); g_string_printf (config_str, "%s/%s/%s", BASE_KEY, MAIN_WIN_SECTION, SORT_ORDER); gconf_client_set_int (client, config_str->str, order, NULL); g_string_free (config_str, TRUE); } static void on_query_changed (GtkWidget *widget, gpointer user_data) { PGconn *conn; gint pk; gint sel; gint prev_sel; GString *config_str; GArray *pks; GConfClient *client; g_assert (widget != NULL); g_assert (user_data != NULL); client = g_object_get_data (G_OBJECT (user_data), MY_GCONF_CLIENT); g_assert (client != NULL); pks = g_object_get_data (G_OBJECT (widget), PK_ARRAY); #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); #else sel = gtk_option_menu_get_history (GTK_OPTION_MENU (widget)); #endif prev_sel = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), PREV_SEL)); g_object_set_data (G_OBJECT (widget), PREV_SEL, GINT_TO_POINTER (sel)); if (pks != NULL && sel != -1 && sel != prev_sel) { pk = g_array_index (pks, gint, sel); config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, curr_db_name->str, MAIN_QUERY); gconf_client_set_int (client, config_str->str, pk, NULL); g_string_free (config_str, TRUE); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); draw_pr_list (GTK_WIDGET (user_data), conn); } } static void on_project_changed (GtkWidget *widget, gpointer user_data) { PGconn *conn; gint pk; gint sel; gint prev_sel; GString *config_str; GArray *pks; GConfClient *client; g_assert (widget != NULL); g_assert (user_data != NULL); client = g_object_get_data (G_OBJECT (user_data), MY_GCONF_CLIENT); g_assert (client != NULL); pks = g_object_get_data (G_OBJECT (widget), PK_ARRAY); #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); #else sel = gtk_option_menu_get_history (GTK_OPTION_MENU (widget)); #endif prev_sel = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), PREV_SEL)); g_object_set_data (G_OBJECT (widget), PREV_SEL, GINT_TO_POINTER (sel)); if (pks != NULL && sel != -1 && sel != prev_sel) { prev_sel = sel; pk = g_array_index (pks, gint, sel); config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, curr_db_name->str, DEF_PROJECT); gconf_client_set_int (client, config_str->str, pk, NULL); g_string_free (config_str, TRUE); conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); draw_pr_list (GTK_WIDGET (user_data), conn); } } static gboolean on_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { PGconn *conn; GtkWidget *main_win = GTK_WIDGET (user_data); GtkTreeModel *model; GtkTreeSelection *sel; GtkTreeIter iter; gint pk_num; g_assert (widget != NULL); g_assert (event != NULL); g_assert (user_data != NULL); if (event != NULL) { switch (event->keyval) { case GDK_KP_Enter: case GDK_ISO_Enter: case GDK_3270_Enter: case GDK_Return: model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); if (gtk_tree_selection_get_selected (sel, NULL, &iter)) { gtk_tree_model_get (model, &iter, RESULT_PK, &pk_num, -1); conn = g_object_get_data (G_OBJECT (main_win), MY_DB_CONN); g_assert (conn != NULL); raise_or_create_pr_update_dlg (main_win, conn, pk_num); } break; default: break; } } return FALSE; } static gboolean on_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { static GtkMenu *popup = NULL; GtkWidget *main_win = GTK_WIDGET (user_data); GtkWidget *item; GtkTreeModel *model; GtkTreeSelection *sel; GtkTreeIter iter; GtkTreePath *path; PGconn *conn; gint pk_num; gboolean handled = FALSE; g_assert (widget != NULL); g_assert (event != NULL); g_assert (user_data != NULL); if (popup == NULL) { popup = GTK_MENU (gtk_menu_new ()); gtk_widget_show (GTK_WIDGET (popup)); item = gtk_menu_item_new_with_label (_("Edit...")); g_signal_connect (item, "activate", G_CALLBACK (on_modify), user_data); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_show (item); #ifdef PRINTING_SUPPORTED item = gtk_menu_item_new_with_label (_("Print...")); g_signal_connect (item, "activate", G_CALLBACK (on_print), user_data); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_show (item); #endif item = gtk_separator_menu_item_new(); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_show (item); item = gtk_menu_item_new_with_label (_("New Problem Report...")); g_signal_connect (item, "activate", G_CALLBACK (on_new_pr), user_data); gtk_menu_shell_append (GTK_MENU_SHELL (popup), item); gtk_widget_show (item); } if (event) { switch (event->button) { case 1: switch (event->type) { case GDK_2BUTTON_PRESS: handled = TRUE; model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); if (gtk_tree_selection_get_selected (sel, NULL, &iter)) { gtk_tree_model_get (model, &iter, RESULT_PK, &pk_num, -1); conn = g_object_get_data (G_OBJECT (main_win), MY_DB_CONN); g_assert (conn != NULL); raise_or_create_pr_update_dlg (main_win, conn, pk_num); } break; default: break; } break; case 2: break; case 3: switch (event->type) { case GDK_BUTTON_PRESS: handled = TRUE; if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, &path, NULL, NULL, NULL)) { sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); gtk_tree_selection_select_path (sel, path); gtk_menu_popup (popup, NULL, NULL, NULL, NULL, event->button, event->time); gtk_tree_path_free (path); } break; default: break; } default: break; } } return handled; } GtkWidget * create_main_win (PGconn *conn, GConfClient *client) { GtkWidget *main_win; GtkWidget *dock1; GtkWidget *vbox1; GtkWidget *vbox2; GtkWidget *project_lbl; GtkWidget *query_lbl; GtkWidget *query_menu; GtkWidget *scrolledwindow2; GtkWidget *results_list_view; GtkListStore *results_list_store; GtkWidget *appbar; GtkWidget *spacing_lbl; GtkWidget *hbox; GtkWidget *prj_menu; GtkWidget *arch_cb; GString *stat_string; GtkTooltips *tooltips; GError *error = NULL; gboolean remember_sizes = remember_window_sizes (client); GString *cfg; gint x; gint y; static GnomeUIInfo toolbar_uiinfo[] = { GNOMEUIINFO_ITEM_STOCK (N_("New PR"), N_("Create a new problem report."), on_new_pr, GTK_STOCK_NEW), GNOMEUIINFO_ITEM_STOCK (N_("Edit PR"), N_("Edit the currently selected problem report."), on_modify, GTK_STOCK_OPEN), GNOMEUIINFO_ITEM_STOCK (N_("Find PRs"), N_("Search for specific problem reports."), on_find, GTK_STOCK_FIND), #ifdef PRINTING_SUPPORTED GNOMEUIINFO_ITEM_STOCK (N_("Print"), N_("Print problem reports."), on_print, GTK_STOCK_PRINT), #endif GNOMEUIINFO_ITEM_STOCK (N_("Refresh"), N_("Refresh the displayed problem reports."), on_refresh_button_clicked, GTK_STOCK_REFRESH), GNOMEUIINFO_ITEM_STOCK (N_("Exit"), N_("Exit PRepS."), on_exit_button_clicked, GTK_STOCK_QUIT), GNOMEUIINFO_END }; static GnomeUIInfo pr_menu_uiinfo[] = { GNOMEUIINFO_MENU_NEW_ITEM (N_("_New Problem Report..."), N_("Create a new problem report."), on_new_pr, NULL), GNOMEUIINFO_ITEM_NONE (N_("_Edit Problem Report..."), N_("Edit the selected problem report."), on_modify), GNOMEUIINFO_ITEM_NONE (N_("_Find Problem Reports..."), N_("Find problem reports based on user defined criteria."), on_find), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_NONE (N_("_Login..."), N_("Log in to a different PRepS database."), on_login), #ifdef PRINTING_SUPPORTED GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_PRINT_ITEM (on_print, NULL), #endif GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_EXIT_ITEM (on_Exit_activate, NULL), GNOMEUIINFO_END }; static GnomeUIInfo admin_menu_uiinfo[] = { GNOMEUIINFO_ITEM_NONE (N_("_Projects..."), N_("Create new projects, or modify the properties of " "existing projects."), on_Projects_activate), GNOMEUIINFO_ITEM_NONE (N_("_Users..."), N_("Create new users, or modify the information for " "existing users."), on_Users_activate), GNOMEUIINFO_ITEM_NONE (N_("_Attributes..."), N_("Create new problem report attributes (severity, status, " "problem type), or modify the existing attributes."), on_Attributes_activate), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_NONE (N_("_Archive Problem Reports..."), N_("Archive problem reports based on user defined criteria."), on_archive), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_NONE (N_("_User Defined Filters..."), N_("Create or modify the display filters defined by the current user."), on_User_query_activate), GNOMEUIINFO_ITEM_NONE (N_("_System Defined Filters..."), N_("Create or modify the display filters defined for all users of " "the system."), on_System_query_activate), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_NONE (N_("P_references..."), N_("Set the user preferences."), on_Properties_activate), GNOMEUIINFO_END }; const gint admin_menu_arch_pos = 4; static GnomeUIInfo rep_menu_uiinfo[] = { GNOMEUIINFO_ITEM_NONE (N_("PRs by _Status..."), N_("Generate an HTML report showing the problem reports " "grouped by status."), on_StatusRpt_activate), GNOMEUIINFO_ITEM_NONE (N_("PRs by _Project Version..."), N_("Generate an HTML report showing the problem reports " "grouped by project versions."), on_VerRpt_activate), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_NONE (N_("ChangeLog..."), N_("Generate a text file ChangeLog template for a selected " " project."), on_ChangeLog_activate), GNOMEUIINFO_END }; static GnomeUIInfo help_menu_uiinfo[] = { GNOMEUIINFO_HELP ("preps"), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_ABOUT_ITEM (on_About_activate, NULL), GNOMEUIINFO_END }; static GnomeUIInfo menubar_uiinfo[] = { GNOMEUIINFO_SUBTREE (N_("_Problem Reports"), pr_menu_uiinfo), GNOMEUIINFO_SUBTREE (N_("_Administration"), admin_menu_uiinfo), GNOMEUIINFO_SUBTREE (N_("_Reports"), rep_menu_uiinfo), GNOMEUIINFO_MENU_HELP_TREE (help_menu_uiinfo), GNOMEUIINFO_END }; g_assert (conn != NULL); g_assert (client != NULL); tooltips = gtk_tooltips_new (); main_win = gnome_app_new (PACKAGE, _("PRepS - Problem Reporting System")); GLADE_HOOKUP_OBJECT_NO_REF (main_win, main_win, MAIN_WIN); gtk_container_set_border_width (GTK_CONTAINER (main_win), 0); gtk_window_set_resizable (GTK_WINDOW (main_win), TRUE); g_signal_connect (main_win, "show", G_CALLBACK (on_main_win_show), NULL); g_signal_connect (main_win, "delete_event", G_CALLBACK (on_main_delete_event), NULL); g_signal_connect (main_win, "destroy", G_CALLBACK (on_main_destroy), NULL); g_object_set_data (G_OBJECT (main_win), MY_DB_CONN, conn); g_object_set_data (G_OBJECT (main_win), MY_GCONF_CLIENT, client); g_object_set_data (G_OBJECT (main_win), ADMIN_USER, GINT_TO_POINTER (get_db_access_lvl (conn))); /* * Since this stuff is set by the system, and not the user, I only * check the last "is_def" for each set. Since the files are editable * by the user, it may not be valid in all cases, but it will still * work. */ cfg = g_string_new (""); if (remember_sizes) { g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, X_POS); x = gconf_client_get_int (client, cfg->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; x = -1; } g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, Y_POS); y = gconf_client_get_int (client, cfg->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; y = -1; } if (x >= 0 && y >= 0) { gtk_window_move (GTK_WINDOW (main_win), x, y); } } if (remember_sizes) { g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, X_SIZE); x = gconf_client_get_int (client, cfg->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; x = DEF_WIDTH; } g_string_printf (cfg, "%s/%s/%s/%s", BASE_KEY, WINSTATES, MAIN_WIN_SEC, Y_SIZE); y = gconf_client_get_int (client, cfg->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; y = DEF_HEIGHT; } } else { x = DEF_WIDTH; y = DEF_HEIGHT; } gtk_window_set_default_size (GTK_WINDOW (main_win), x, y); dock1 = GNOME_APP (main_win)->dock; GLADE_HOOKUP_OBJECT (main_win, dock1, "dock1"); gtk_widget_show (dock1); gnome_app_create_menus_with_data (GNOME_APP (main_win), menubar_uiinfo, main_win); gnome_app_create_toolbar_with_data (GNOME_APP (main_win), toolbar_uiinfo, main_win); /* * Save off menu items that we may have to make active or inactive. */ GLADE_HOOKUP_OBJECT_NO_REF (main_win, admin_menu_uiinfo[admin_menu_arch_pos].widget, ARCH_MENU_ITEM); refresh_menu_access (main_win); vbox1 = gtk_vbox_new (FALSE, 0); GLADE_HOOKUP_OBJECT (main_win, vbox1, "vbox1"); gtk_widget_show (vbox1); gnome_app_set_contents (GNOME_APP (main_win), vbox1); vbox2 = gtk_vbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (main_win, vbox2, "dtl_vbox"); gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox2), STD_DLG_BORDER); gtk_widget_show (vbox2); hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0); GLADE_HOOKUP_OBJECT (main_win, hbox, "query_hbox"); gtk_widget_show (hbox); query_lbl = gtk_label_new (_("Display:")); GLADE_HOOKUP_OBJECT (main_win, query_lbl, "query_hbox"); gtk_misc_set_alignment (GTK_MISC (query_lbl), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox), query_lbl, FALSE, FALSE, 0); gtk_widget_show (query_lbl); #ifdef USE_NEW_GTK query_menu = gtk_combo_box_new_text (); #else query_menu = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (main_win, query_menu, QUERY_MENU); gtk_box_pack_start (GTK_BOX (hbox), query_menu, FALSE, FALSE, 0); gtk_widget_show (query_menu); spacing_lbl = gtk_label_new (" "); gtk_box_pack_start (GTK_BOX (hbox), spacing_lbl, FALSE, FALSE, 0); gtk_widget_show (spacing_lbl); project_lbl = gtk_label_new (_("Limit to project:")); GLADE_HOOKUP_OBJECT (main_win, project_lbl, "project_hbox"); gtk_misc_set_alignment (GTK_MISC (project_lbl), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox), project_lbl, FALSE, FALSE, 0); gtk_widget_show (project_lbl); #ifdef USE_NEW_GTK prj_menu = gtk_combo_box_new_text (); #else prj_menu = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (main_win, prj_menu, PROJECT_MENU); gtk_box_pack_start (GTK_BOX (hbox), prj_menu, FALSE, FALSE, 0); gtk_widget_show (prj_menu); arch_cb = gtk_check_button_new_with_label (_("Display Archived Problem Reports")); GLADE_HOOKUP_OBJECT (main_win, arch_cb, DISPLAY_ARCH_CB); gtk_box_pack_start (GTK_BOX (vbox2), arch_cb, FALSE, FALSE, 0); gtk_widget_show (arch_cb); scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); GLADE_HOOKUP_OBJECT (main_win, scrolledwindow2, "scrolledwindow2"); gtk_widget_show (scrolledwindow2); gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow2, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_SHADOW_IN); results_list_store = gtk_list_store_new (NUM_RESULT_COLS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_BOOLEAN); results_list_view = GTK_WIDGET (create_results_tree_view (GTK_TREE_MODEL (results_list_store), main_win)); set_sort_order (GTK_TREE_SORTABLE (results_list_store), client); g_signal_connect (results_list_store, "sort-column-changed", G_CALLBACK (on_sort_changed), main_win); GLADE_HOOKUP_OBJECT (main_win, results_list_view, RESULTS_LIST_VIEW); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (results_list_view), TRUE); gtk_container_add (GTK_CONTAINER (scrolledwindow2), results_list_view); gtk_widget_show (results_list_view); g_signal_connect (results_list_view, "button_press_event", G_CALLBACK (on_button_press_event), main_win); g_signal_connect (results_list_view, "key_press_event", G_CALLBACK (on_key_press_event), main_win); appbar = gnome_appbar_new (FALSE, TRUE, GNOME_PREFERENCES_NEVER); GLADE_HOOKUP_OBJECT (main_win, appbar, APPBAR); gtk_widget_show (appbar); gnome_app_set_statusbar (GNOME_APP (main_win), appbar); gnome_app_install_menu_hints (GNOME_APP (main_win), menubar_uiinfo); stat_string = g_string_new (""); g_string_printf (stat_string, DEFAULT_STAT_STRING, curr_db_name->str); gnome_appbar_set_default (GNOME_APPBAR (appbar), stat_string->str); g_string_free (stat_string, TRUE); setup_gconf_notify_handlers (client, main_win); g_object_set_data (G_OBJECT (main_win), "tooltips", tooltips); return main_win; }