/*------------------------------------------------------------------------- * Copyright (c) 1999-2005 Kenneth W. Sodemann (stuffle@mac.com) *------------------------------------------------------------------------- * probupdate_dlg * * Synopsis: * Handle updates to, and viewing of existing problem reports. * * $Id: probupdate_dlg.c,v 1.76 2005/05/15 19:12:35 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 "audit_trail.h" #include "db_utils.h" #include "defs.h" #include "error_chks.h" #include "gstr_utils.h" #include "gtkutils.h" #include "mainwin.h" #include "probupdate_dlg.h" #include "sqlstr.h" #include "util.h" /* * Define the names of some of the key widgets. */ #define SUBMTTR_LABEL "submttr_label" #define TITLE_LABEL "title_label" #define RESPONSIBLE_COMBO "responsible_combo" #define SUBJECT_ENTRY "subject_entry" #define STATUS_COMBO "status_combo" #define SEVERITY_COMBO "severity_combo" #define FIX_VER_COMBO "fix_ver_combo" #define PROJECT_COMBO "project_combo" #define VERSION_COMBO "version_combo" #define PRBTYPE_COMBO "prbtype_combo" #define PK_LIST "pk_list" #define DEF_OPEN_VER_LIST "def_open_ver_list" #define DEF_SEVR_LIST "def_sevr_list" #define NELS "number_of_elments" #define DESCR_EDIT "descr_edit" #define FIX_DESCR_EDIT "fix_descr_edit" #define AUDIT_TRAIL_EDIT "aud_tr_edit" #define CHANGE_LOG_TEXT "change_log_text" #define FIX_TAB_LBL "fix_tab_label" #define CHGLOG_TAB_LBL "chglog_tab_label" #define FIX_TAB_CHAR_CNT "fix_tab_char_cnt" #define CHGLOG_TAB_CHAR_CNT "chglog_tab_char_cnt" #define RESET_DEF_VER_ID "reset_def_ver_id" #define FIX_DESCR _("Fix Description") #define FIX_DESCR_STAR _("Fix Description*") #define CHGLOG_DESCR _("ChangeLog Text") #define CHGLOG_DESCR_STAR _("ChangeLog Text*") #define RESP_NOBODY_NAME _("") #define RESP_NOBODY_ID "" #define TITLE_STRING _("Problem Report #%d") #define CLIST_START 7 #define CLIST_END 10 /* * This "locking" is voluntary, but it seems to work much nicer than the * current levels of locking available from PostgreSQL. The basic idea * here is to run the CREATE_LOCK query, then check and make sure that * the locker is you. If the locker is someone else, they had it first. * * REMOVE_LOCK must be run before the dialog exits. */ #define CREATE_LOCK "\ UPDATE problem_report \ SET locker_id = getpgusername () \ WHERE locker_id is NULL \ AND problem_num = %d " #define SELECT_LOCKER "\ SELECT pr.locker_id, \ p.last_name || ', ' || p.first_name || ' (' || pr.locker_id || ')' \ FROM problem_report pr, person p \ WHERE p.login_id = pr.locker_id \ AND problem_num = %d " #define REMOVE_LOCK "\ UPDATE problem_report \ SET locker_id = NULL \ WHERE locker_id = getpgusername () \ AND problem_num = %d " /* * Get all of the information that we need for the problem report. */ #define PRJ_NUM_POS 0 #define PRJ_NAME_POS 1 #define SUBMITTER_ID_POS 2 #define RESPONSIBLE_ID_POS 3 #define TITLE_POS 4 #define DESCR_POS 5 #define FIX_POS 6 #define SEVERITY_NUM_POS 7 #define STATUS_NUM_POS 8 #define PROB_TYPE_POS 9 #define OPEN_VER_POS 10 #define FIX_VER_POS 11 #define CHANGE_LOG_TEXT_POS 12 #define SELECT_PR_DATA "\ SELECT pr.project_num, prj.name, \ p.last_name||', '|| p.first_name||' ('||pr.submitter_id||')', \ pr.responsible_id, pr.title, pr.descr, pr.fix, pr.severity_num, \ pr.status_num, pt.type_num, pr.open_version, pr.close_version, \ pr.change_log_text \ FROM problem_report pr, project prj, person p, problem_type pt \ WHERE pt.type_num = pr.type_num \ AND p.login_id = pr.submitter_id \ AND prj.project_num = pr.project_num \ AND pr.problem_num = %d " #define FULL_NAME_POS 4 #define SEL_RESP_PRJ "\ SELECT DISTINCT 0, 1, 2, p.login_id, \ p.last_name||', '||p.first_name||' ('||p.login_id||')' \ FROM responsible r, person p \ WHERE p.login_id = r.login_id \ AND r.project_num = %d \ ORDER BY 5, 4" #define SEL_RESP_PRUPD "\ SELECT DISTINCT 0, 1, 2, p.login_id, \ p.last_name||', '||p.first_name||' ('||p.login_id||')' \ FROM responsible r, person p \ WHERE (p.login_id = r.login_id OR \ p.login_id = '%s') \ AND r.project_num = %d \ ORDER BY 5, 4" /* * 'Null' version display data (for the version related stuff). */ #define NULL_NAME "" typedef enum { STAT_ATTR, SEVR_ATTR, PR_TYPE_ATTR } AttrType; /*---------------------------------------------------------------------- * Local Function Prototypes. *--------------------------------------------------------------------*/ static void append_sql_insert (GString *ins_sql, GString *val_sql, const gchar *colname, const gchar *value, gboolean first); static void append_sql_update (GString *sql, const gchar *colname, const gchar *value, gboolean first); static gboolean apply_changes (GtkDialog *dlg); static gboolean apply_lock (GtkDialog *dlg, PGconn *conn, gint pk_num); static void check_chglog_tab_text (GtkTextBuffer *buff, gpointer user_data); static void check_fix_tab_text (GtkTextBuffer *buff, gpointer user_data); static void convert_to_update_mode (GtkWidget *dlg); static void draw_audit_trail (GtkTextView *view, PGconn *conn, gint pr_pk); #ifdef USE_NEW_GTK static void init_assignee_combo (GtkComboBox *combo, PGconn *conn, gint prj_pk, const char *user_id); static void init_attr_combo (GtkComboBox *stat_combo, AttrType attr_type, GConfClient *client, PGconn *conn, gint pr_pk, gint attr_pk); static void init_prj_combo (GtkComboBox *combo, GConfClient *client, PGconn *conn, gint prj_pk, gint pr_pk); static void init_prj_ver_combo (GtkComboBox *combo, PGconn *conn, gint prj_pk, gint ver_num); #else static void init_assignee_combo (GtkOptionMenu *combo, PGconn *conn, gint prj_pk, const char *user_id); static void init_attr_combo (GtkOptionMenu *stat_combo, AttrType attr_type, GConfClient *client, PGconn *conn, gint pr_pk, gint attr_pk); static void init_prj_combo (GtkOptionMenu *combo, GConfClient *client, PGconn *conn, gint prj_pk, gint pr_pk); static void init_prj_ver_combo (GtkOptionMenu *combo, PGconn *conn, gint prj_pk, gint ver_num); #endif static gboolean min_text_entered (GtkWidget *dlg); static void on_pr_dlg_show_for_updpr (GtkWidget *widget, gpointer user_data); static void on_pr_dlg_destroy (GObject *object, gpointer user_data); static void on_cancel_button_clicked (GtkDialog *dlg); static void on_pr_dlg_clicked (GtkDialog *dlg, gint btn_cd, gpointer user_data); static void on_project_changed (GtkWidget *prj_combo, GtkWidget *dlg); static void reset_def_ver (GtkWidget *prj_ver_combo, GtkWidget *dlg); static void remove_lock (PGconn *conn, gint pk_num); static void set_default_severity (GtkWidget *pt_combo, GtkWidget *dlg); static gboolean submitter_access_only (PGconn *conn, gint prnum); /*-------------------------------------------------------------------------- * Lock functions * * PRepS uses a home made "locking" mechanism that indicates which user * is currently allowed to edit a particular problem report. These * functions deal with those locks. *-------------------------------------------------------------------------- */ static gboolean apply_lock (GtkDialog *dlg, PGconn *conn, gint pk_num) { GString *sql_buffer; PGresult *tmp_res; gboolean in_error; gboolean locked_by_other = FALSE; START_TRANSACTION (conn); sql_buffer = g_string_new (""); g_string_printf (sql_buffer, CREATE_LOCK, pk_num); tmp_res = PQexec (conn, sql_buffer->str); in_error = !chk_sql_error (tmp_res, "Creating voluntary lock"); if (in_error) { ROLLBACK (conn); } else { COMMIT (conn); } PQclear (tmp_res); if (!in_error) { g_string_printf (sql_buffer, SELECT_LOCKER, pk_num); tmp_res = PQexec (conn, sql_buffer->str); in_error = !chk_sql_error (tmp_res, "Checking the lock status"); if (!in_error) { if (strcmp (PQuser (conn), PQgetvalue (tmp_res, 0, 0))) { GString *msg_str; GtkWidget *msg_dlg; msg_str = g_string_new (""); g_string_printf (msg_str, _("The selected problem report is locked by: %s\n"), PQgetvalue (tmp_res, 0, 1)); msg_str = g_string_append (msg_str, _("The problem report will be opened for viewing only.")); msg_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (msg_dlg)); g_string_free (msg_str, TRUE); locked_by_other = TRUE; } } PQclear (tmp_res); } g_string_free (sql_buffer, TRUE); return (!in_error && !locked_by_other); } static void remove_lock (PGconn *conn, gint pk_num) { GString *sql; PGresult *res; sql= g_string_new (""); START_TRANSACTION (conn); g_string_printf (sql, REMOVE_LOCK, pk_num); res = PQexec (conn, sql->str); chk_sql_error (res, "Removing lock"); COMMIT (conn); PQclear (res); g_string_free (sql, TRUE); } /*-------------------------------------------------------------------------- * Draw Functions * * Functions used to "draw" or "populate" certain widgets. This includes * functions used to initialize combos. *-------------------------------------------------------------------------- */ static void draw_audit_trail (GtkTextView *view, PGconn *conn, gint pr_pk) { GtkTextBuffer *buff; GtkTextIter end; GString *sql_buffer; PGresult *res; gint i, n; buff = gtk_text_view_get_buffer (view); sql_buffer = g_string_new (""); g_string_printf (sql_buffer, PR_SUBMIT_DATE_QUERY, pr_pk); res = PQexec (conn, sql_buffer->str); if (chk_sql_error (res, "Getting open line")) { g_assert (PQntuples (res) == 1); gtk_text_buffer_set_text (buff, PQgetvalue (res, 0, 0), -1); gtk_text_buffer_get_end_iter (buff, &end); gtk_text_buffer_insert (buff, &end, "\n", -1); } PQclear (res); g_string_printf (sql_buffer, SELECT_AUDIT_TRAIL, pr_pk, pr_pk); res = PQexec (conn, sql_buffer->str); if (chk_sql_error (res, "Getting Audit Trail Data")) { n = PQntuples (res); for (i = 0; i < n; i++) { gtk_text_buffer_insert (buff, &end, PQgetvalue (res, i, 0), -1); gtk_text_buffer_insert (buff, &end, "\n", -1); } } g_string_free (sql_buffer, TRUE); PQclear (res); } static void #ifdef USE_NEW_GTK init_assignee_combo (GtkComboBox *combo, PGconn *conn, gint prj_pk, const char *user_id) #else init_assignee_combo (GtkOptionMenu *combo, PGconn *conn, gint prj_pk, const char *user_id) #endif { GString *sql; gint sel; PGresult *res; gint i; gint n; #ifndef USE_NEW_GTK GtkWidget *menu; GtkWidget *item; #endif GList *pk_list = NULL; GList *list_iter; GString *id; /* * If elements already exist for this combo, remove them first. */ n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), NELS)); if (n > 0) { #ifdef USE_NEW_GTK for (i = 0; i < n; i++) { gtk_combo_box_remove_text (combo, n - i - 1); } #else gtk_option_menu_remove_menu (combo); #endif pk_list = g_object_get_data (G_OBJECT (combo), PK_LIST); g_assert (pk_list != NULL); for (list_iter = g_list_first (pk_list); list_iter != NULL; list_iter = list_iter->next) { g_string_free ((GString *)list_iter->data, TRUE); } g_list_free (pk_list); pk_list = NULL; } /* * Old stuff is freed up, start building the new combo item. */ sql = g_string_new (""); if (user_id == NULL || user_id[0] == '\0') { g_string_printf (sql, SEL_RESP_PRJ, prj_pk); } else { g_string_printf (sql, SEL_RESP_PRUPD, user_id, prj_pk); } res = PQexec (conn, sql->str); sel = 0; if (chk_sql_error (res, "Getting responsible list")) { #ifndef USE_NEW_GTK menu = gtk_menu_new (); #endif sel = 0; /* * Get all of the names. Create a list of login id's. This * list MUST be in the same order as the associated option * menu, and will be destroyed when the dialog is destroyed. * * First load the NOBODY person. */ id = g_string_new (RESP_NOBODY_ID); pk_list = g_list_append (pk_list, id); #ifdef USE_NEW_GTK gtk_combo_box_append_text (combo, RESP_NOBODY_NAME); #else item = gtk_menu_item_new_with_label (RESP_NOBODY_NAME); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); #endif /* * get all of the actual people */ n = PQntuples (res); for (i = 0; i < n; i++) { id = g_string_new (PQgetvalue (res, i, RESPONSIBLE_ID_POS)); pk_list = g_list_append (pk_list, id); if (user_id != NULL && user_id[0] != '\0') { sel = (strcmp (id->str, user_id) == 0) ? i + 1 : sel; } #ifdef USE_NEW_GTK gtk_combo_box_append_text (combo, PQgetvalue (res, i, FULL_NAME_POS)); #else item = gtk_menu_item_new_with_label (PQgetvalue (res, i, FULL_NAME_POS)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); #endif } g_object_set_data (G_OBJECT (combo), PK_LIST, pk_list); g_object_set_data (G_OBJECT (combo), NELS, GINT_TO_POINTER (n + 1)); #ifdef USE_NEW_GTK gtk_combo_box_set_active (combo, sel); #else gtk_option_menu_set_menu (combo, menu); gtk_option_menu_set_history (combo, sel); #endif } PQclear (res); g_string_free (sql, TRUE); } /* * Initialize the attribute combo box. * combo - the combo widget * attr_type - the type of attributes (stat, sevr, prob type) * client - conf client, used to determine sorting opt setting * conn - the database connection * pr_pk - the PR number, used when initializing for existing PR's * so the currently set attribute will be displayed even * if it is not active. * attr_pk - the combo will be initialized to display the element * with this PK if the particular element is part of the * fetched set. Otherwise the combo will be initialized * with the first element selected. */ static void #ifdef USE_NEW_GTK init_attr_combo (GtkComboBox *combo, AttrType attr_type, GConfClient *client, PGconn *conn, gint pr_pk, gint attr_pk) #else init_attr_combo (GtkOptionMenu *combo, AttrType attr_type, GConfClient *client, PGconn *conn, gint pr_pk, gint attr_pk) #endif { GString *sql; gboolean updating; gint sel; PGresult *res; gint i; gint n; gint pk; gint def_sevr_pk; #ifndef USE_NEW_GTK GtkWidget *menu; GtkWidget *item; #endif GList *pk_list = NULL; GList *def_sevr_list = NULL; updating = (pr_pk != INVALID_PK); sql = g_string_new (""); if (attr_type == STAT_ATTR) { stat_sql_str (sql, (updating ? ACTIVE_ITEMS_PLUS_IN_USE : ACTIVE_ITEMS_ONLY), client, pr_pk); } else if (attr_type == SEVR_ATTR) { sevr_sql_str (sql, (updating ? ACTIVE_ITEMS_PLUS_IN_USE : ACTIVE_ITEMS_ONLY), client, pr_pk); } else if (attr_type == PR_TYPE_ATTR) { pr_type_sql_str (sql, (updating ? ACTIVE_ITEMS_PLUS_IN_USE : ACTIVE_ITEMS_ONLY), client, pr_pk); } else { g_assert_not_reached(); } sel = 0; res = PQexec (conn, sql->str); if (chk_sql_error (res, "Filling the combo")) { #ifndef USE_NEW_GTK menu = gtk_menu_new (); #endif n = PQntuples (res); for (i = 0; i < n; i++) { pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); /* * If the PK of the current attribute matches the one we are * looking for, we will need to select it when we are all * done. */ sel = (pk == attr_pk) ? i : sel; pk_list = g_list_append (pk_list, GINT_TO_POINTER (pk)); #ifdef USE_NEW_GTK gtk_combo_box_append_text (combo, PQgetvalue (res, i, SQLSTR_NAME_POS)); #else 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); #endif /* * If this is the problem type dialog, we also need to * build a list of default severities. */ if (attr_type == PR_TYPE_ATTR) { def_sevr_pk = atoi (PQgetvalue (res, i, SQLSTR_DEFSEVR_POS)); def_sevr_list = g_list_append (def_sevr_list, GINT_TO_POINTER (def_sevr_pk)); } } g_object_set_data (G_OBJECT (combo), PK_LIST, pk_list); g_object_set_data (G_OBJECT (combo), NELS, GINT_TO_POINTER (n)); if (attr_type == PR_TYPE_ATTR) { g_object_set_data (G_OBJECT (combo), DEF_SEVR_LIST, def_sevr_list); } #ifdef USE_NEW_GTK gtk_combo_box_set_active (combo, sel); #else gtk_option_menu_set_menu (combo, menu); gtk_option_menu_set_history (combo, sel); #endif } PQclear (res); g_string_free (sql, TRUE); } static void #ifdef USE_NEW_GTK init_prj_combo (GtkComboBox *combo, GConfClient *client, PGconn *conn, gint prj_pk, gint pr_pk) #else init_prj_combo (GtkOptionMenu *combo, GConfClient *client, PGconn *conn, gint prj_pk, gint pr_pk) #endif { #ifndef USE_NEW_GTK GtkWidget *menu; GtkWidget *item; #endif queryLevel lvl; GString *sql; PGresult *res; gboolean updating; gint i; gint n; gint pk; gint def_open_ver; gint sel; GList *pk_list = NULL; GList *ver_list = NULL; sql = g_string_new (""); updating = (pr_pk != INVALID_PK); lvl = (updating ? ACTIVE_ITEMS_PLUS_IN_USE : ACTIVE_ITEMS_ONLY); prj_sql_str (sql, lvl, TRUE, !updating, updating, FALSE, client, pr_pk); sel = 0; res = PQexec (conn, sql->str); if (chk_sql_error (res, "Fill Project Combo")) { #ifndef USE_NEW_GTK menu = gtk_menu_new (); #endif n = PQntuples (res); for (i = 0; i < n; i++) { pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); if (PQgetisnull (res, i, SQLSTR_DEFOPENVER_POS)) { def_open_ver = INVALID_PK; } else { def_open_ver = atoi (PQgetvalue (res, i, SQLSTR_DEFOPENVER_POS)); } pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); /* * If the PK of the current project matches the one we are looking * for, we will need to select it when we are done. */ sel = (pk == prj_pk) ? i : sel; pk_list = g_list_append (pk_list, GINT_TO_POINTER (pk)); ver_list = g_list_append (ver_list, GINT_TO_POINTER (def_open_ver)); #ifdef USE_NEW_GTK gtk_combo_box_append_text (combo, PQgetvalue (res, i, SQLSTR_NAME_POS)); #else 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); #endif } g_object_set_data (G_OBJECT (combo), PK_LIST, pk_list); g_object_set_data (G_OBJECT (combo), DEF_OPEN_VER_LIST, ver_list); g_object_set_data (G_OBJECT (combo), NELS, GINT_TO_POINTER (n)); #ifdef USE_NEW_GTK gtk_combo_box_set_active (combo, sel); #else gtk_option_menu_set_menu (combo, menu); gtk_option_menu_set_history (combo, sel); #endif } PQclear (res); g_string_free (sql, TRUE); } static void #ifdef USE_NEW_GTK init_prj_ver_combo (GtkComboBox *combo, PGconn *conn, gint prj_pk, gint ver_num) #else init_prj_ver_combo (GtkOptionMenu *combo, PGconn *conn, gint prj_pk, gint ver_num) #endif { #ifndef USE_NEW_GTK GtkWidget *menu; GtkWidget *item; #endif queryLevel lvl; GString *sql; PGresult *res; gboolean updating; gint i; gint n; gint pk; gint sel; GList *pk_list = NULL; gulong id; /* * If this combo was a reset_def_ver handler, block it while we are * initializing the combo. */ id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), RESET_DEF_VER_ID)); if (id != 0) { g_signal_handler_block (combo, id); } /* * First, if current data exists, we need to destroy it. */ n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), NELS)); if (n > 0) { pk_list = g_object_get_data (G_OBJECT (combo), PK_LIST); g_assert (pk_list != NULL); #ifdef USE_NEW_GTK for (i = 0; i < n; i++) { gtk_combo_box_remove_text (combo, n - i - 1); } #else gtk_option_menu_remove_menu (combo); #endif g_list_free (pk_list); pk_list = NULL; } /* * Build the combo with the new data. */ sql = g_string_new (""); updating = (ver_num != INVALID_PK); lvl = (updating ? ACTIVE_ITEMS_PLUS_IN_USE : ACTIVE_ITEMS_ONLY); prj_ver_sql_str (sql, lvl, prj_pk, ver_num); sel = 0; res = PQexec (conn, sql->str); if (chk_sql_error (res, "Fill Project Combo")) { #ifndef USE_NEW_GTK menu = gtk_menu_new (); #endif /* * Start with the NULL version. */ pk_list = g_list_append (pk_list, GINT_TO_POINTER (INVALID_PK)); #ifdef USE_NEW_GTK gtk_combo_box_append_text (combo, NULL_NAME); #else item = gtk_menu_item_new_with_label (NULL_NAME); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); #endif n = PQntuples (res); for (i = 0; i < n; i++) { pk = atoi (PQgetvalue (res, i, SQLSTR_PK_POS)); /* * If the PK of the current project matches the one we are looking * for, we will need to select it when we are done. * * Since the first item in the combo is the NULL version, we need * to add 1 to the index when we find a match. */ sel = (pk == ver_num) ? i + 1 : sel; pk_list = g_list_append (pk_list, GINT_TO_POINTER (pk)); #ifdef USE_NEW_GTK gtk_combo_box_append_text (combo, PQgetvalue (res, i, SQLSTR_NAME_POS)); #else 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); #endif } g_object_set_data (G_OBJECT (combo), PK_LIST, pk_list); g_object_set_data (G_OBJECT (combo), NELS, GINT_TO_POINTER (n + 1)); #ifdef USE_NEW_GTK gtk_combo_box_set_active (combo, sel); #else gtk_option_menu_set_menu (combo, menu); gtk_option_menu_set_history (combo, sel); #endif } PQclear (res); g_string_free (sql, TRUE); if (id != 0) { g_signal_handler_unblock (combo, id); } } /*-------------------------------------------------------------------------- *-------------------------------------------------------------------------- */ static gboolean submitter_access_only (PGconn *conn, gint prnum) { PGresult *res; GString *sql; gint n = 0; sql = g_string_new ("select count (*) "); sql = g_string_append (sql, "from submitter s, problem_report pr, "); sql = g_string_append (sql, "project p "); sql = g_string_append (sql, "where p.project_num = pr.project_num "); sql = g_string_append (sql, "and p.login_id <> getpgusername() "); sql = g_string_append (sql, "and s.project_num = pr.project_num "); sql = g_string_append (sql, "and s.login_id = getpgusername() "); g_string_append_printf (sql, "and pr.problem_num = %d ", prnum); sql = g_string_append (sql, "and not exists ( "); sql = g_string_append (sql, "select 'x' from responsible "); sql = g_string_append (sql, "where login_id = s.login_id "); sql = g_string_append (sql, "and project_num = s.project_num) "); res = PQexec (conn, sql->str); if (chk_sql_error (res, _("Determine if submitter only"))) { n = atoi (PQgetvalue (res, 0, 0)); } PQclear (res); g_string_free (sql, TRUE); return (n > 0); } /*-------------------------------------------------------------------------- * Widget Show and Destroy Handlers *-------------------------------------------------------------------------- */ static void on_pr_dlg_show_for_newpr (GtkWidget *widget, gpointer user_data) { GtkLabel *submitter_lbl; #ifdef USE_NEW_GTK GtkComboBox *project_combo; GtkComboBox *version_combo; GtkComboBox *prbtype_combo; GtkComboBox *responsible_combo; GtkComboBox *severity_combo; GtkComboBox *status_combo; GtkComboBox *fix_ver_combo; #else GtkOptionMenu *project_combo; GtkOptionMenu *version_combo; GtkOptionMenu *prbtype_combo; GtkOptionMenu *responsible_combo; GtkOptionMenu *severity_combo; GtkOptionMenu *status_combo; GtkOptionMenu *fix_ver_combo; #endif GList *pk_list; GList *list_iter; GtkEntry *subject_entry; PGconn *conn; gint pr_pk; /* the pk_num of the problem report */ gint targ_pk; /* target PK used to init combo values */ gint prj_pk = INVALID_PK; /* the project */ gint sel; GConfClient *client; /* * Get pointers to the widgets that we need to fill. */ submitter_lbl = GTK_LABEL (lookup_widget (widget, SUBMTTR_LABEL)); #ifdef USE_NEW_GTK responsible_combo = GTK_COMBO_BOX (lookup_widget (widget, RESPONSIBLE_COMBO)); severity_combo = GTK_COMBO_BOX (lookup_widget (widget, SEVERITY_COMBO)); status_combo = GTK_COMBO_BOX (lookup_widget (widget, STATUS_COMBO)); fix_ver_combo = GTK_COMBO_BOX (lookup_widget (widget, FIX_VER_COMBO)); project_combo = GTK_COMBO_BOX (lookup_widget (widget, PROJECT_COMBO)); version_combo = GTK_COMBO_BOX (lookup_widget (widget, VERSION_COMBO)); prbtype_combo = GTK_COMBO_BOX (lookup_widget (widget, PRBTYPE_COMBO)); #else responsible_combo = GTK_OPTION_MENU (lookup_widget (widget, RESPONSIBLE_COMBO)); severity_combo = GTK_OPTION_MENU (lookup_widget (widget, SEVERITY_COMBO)); status_combo = GTK_OPTION_MENU (lookup_widget (widget, STATUS_COMBO)); fix_ver_combo = GTK_OPTION_MENU (lookup_widget (widget, FIX_VER_COMBO)); project_combo = GTK_OPTION_MENU (lookup_widget (widget, PROJECT_COMBO)); version_combo = GTK_OPTION_MENU (lookup_widget (widget, VERSION_COMBO)); prbtype_combo = GTK_OPTION_MENU (lookup_widget (widget, PRBTYPE_COMBO)); #endif subject_entry = GTK_ENTRY (lookup_widget (widget, SUBJECT_ENTRY)); g_assert (submitter_lbl != NULL); g_assert (project_combo != NULL); g_assert (version_combo != NULL); g_assert (prbtype_combo != NULL); g_assert (responsible_combo != NULL); g_assert (severity_combo != NULL); g_assert (status_combo != NULL); g_assert (subject_entry != NULL); g_assert (fix_ver_combo != NULL); client = g_object_get_data (G_OBJECT (widget), MY_GCONF_CLIENT); g_assert (client != NULL); conn = g_object_get_data (G_OBJECT (widget), MY_DB_CONN); g_assert (conn != NULL); pr_pk = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), PK_NUM)); g_assert (pr_pk == INVALID_PK); init_attr_combo (prbtype_combo, PR_TYPE_ATTR, client, conn, pr_pk, INVALID_PK); #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (prbtype_combo); #else sel = gtk_option_menu_get_history (prbtype_combo); #endif pk_list = g_object_get_data (G_OBJECT (prbtype_combo), DEF_SEVR_LIST); list_iter = g_list_nth (pk_list, sel); targ_pk = GPOINTER_TO_INT (list_iter->data); init_attr_combo (severity_combo, SEVR_ATTR, client, conn, pr_pk, targ_pk); init_attr_combo (status_combo, STAT_ATTR, client, conn, pr_pk, INVALID_PK); init_prj_combo (project_combo, client, conn, INVALID_PK, pr_pk); #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (project_combo); #else sel = gtk_option_menu_get_history (project_combo); #endif pk_list = g_object_get_data (G_OBJECT (project_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); prj_pk = GPOINTER_TO_INT (list_iter->data); init_assignee_combo (responsible_combo, conn, prj_pk, NULL); pk_list = g_object_get_data (G_OBJECT (project_combo), DEF_OPEN_VER_LIST); list_iter = g_list_nth (pk_list, sel); targ_pk = GPOINTER_TO_INT (list_iter->data); init_prj_ver_combo (version_combo, conn, prj_pk, targ_pk); init_prj_ver_combo (fix_ver_combo, conn, prj_pk, INVALID_PK); set_all_clean (G_OBJECT (widget)); gtk_dialog_set_response_sensitive (GTK_DIALOG (widget), GTK_RESPONSE_OK, FALSE); gtk_dialog_set_response_sensitive (GTK_DIALOG (widget), GTK_RESPONSE_APPLY, FALSE); /* * Connect signal handlers that depend on the widgets being * initialized. */ g_signal_connect (prbtype_combo, "changed", G_CALLBACK (set_default_severity), widget); g_signal_connect (project_combo, "changed", G_CALLBACK (on_project_changed), widget); } static void on_pr_dlg_show_for_updpr (GtkWidget *widget, gpointer user_data) { GtkLabel *submitter_lbl; #ifdef USE_NEW_GTK GtkComboBox *project_combo; GtkComboBox *version_combo; GtkComboBox *prbtype_combo; GtkComboBox *responsible_combo; GtkComboBox *severity_combo; GtkComboBox *status_combo; GtkComboBox *fix_ver_combo; #else GtkOptionMenu *project_combo; GtkOptionMenu *version_combo; GtkOptionMenu *prbtype_combo; GtkOptionMenu *responsible_combo; GtkOptionMenu *severity_combo; GtkOptionMenu *status_combo; GtkOptionMenu *fix_ver_combo; #endif GtkEntry *subject_entry; GtkTextView *descr_text; GtkTextView *fix_text; GtkTextView *change_log_text; GtkTextView *au_tr_text; GtkTextBuffer *buff; GtkLabel *lbl; GString *str; GString *sql_buffer; GString *resp_id; PGresult *main_res = NULL; /* main PR select result */ gboolean in_error = FALSE; gint txt_len; PGconn *conn; gint pr_pk; /* the pk_num of the problem report */ gint pk; /* temp PK used for populating combos */ gint targ_pk; /* target PK used to init combo values */ gint prj_pk = INVALID_PK; /* the project */ GConfClient *client; /* * Get pointers to the widgets that we need to fill. */ submitter_lbl = GTK_LABEL (lookup_widget (widget, SUBMTTR_LABEL)); #ifdef USE_NEW_GTK responsible_combo = GTK_COMBO_BOX (lookup_widget (widget, RESPONSIBLE_COMBO)); severity_combo = GTK_COMBO_BOX (lookup_widget (widget, SEVERITY_COMBO)); status_combo = GTK_COMBO_BOX (lookup_widget (widget, STATUS_COMBO)); fix_ver_combo = GTK_COMBO_BOX (lookup_widget (widget, FIX_VER_COMBO)); project_combo = GTK_COMBO_BOX (lookup_widget (widget, PROJECT_COMBO)); version_combo = GTK_COMBO_BOX (lookup_widget (widget, VERSION_COMBO)); prbtype_combo = GTK_COMBO_BOX (lookup_widget (widget, PRBTYPE_COMBO)); #else responsible_combo = GTK_OPTION_MENU (lookup_widget (widget, RESPONSIBLE_COMBO)); severity_combo = GTK_OPTION_MENU (lookup_widget (widget, SEVERITY_COMBO)); status_combo = GTK_OPTION_MENU (lookup_widget (widget, STATUS_COMBO)); fix_ver_combo = GTK_OPTION_MENU (lookup_widget (widget, FIX_VER_COMBO)); project_combo = GTK_OPTION_MENU (lookup_widget (widget, PROJECT_COMBO)); version_combo = GTK_OPTION_MENU (lookup_widget (widget, VERSION_COMBO)); prbtype_combo = GTK_OPTION_MENU (lookup_widget (widget, PRBTYPE_COMBO)); #endif subject_entry = GTK_ENTRY (lookup_widget (widget, SUBJECT_ENTRY)); descr_text = GTK_TEXT_VIEW (lookup_widget (widget, DESCR_EDIT)); fix_text = GTK_TEXT_VIEW (lookup_widget (widget, FIX_DESCR_EDIT)); change_log_text = GTK_TEXT_VIEW (lookup_widget (widget, CHANGE_LOG_TEXT)); au_tr_text = GTK_TEXT_VIEW (lookup_widget (widget, AUDIT_TRAIL_EDIT)); g_assert (submitter_lbl != NULL); g_assert (project_combo != NULL); g_assert (version_combo != NULL); g_assert (prbtype_combo != NULL); g_assert (responsible_combo != NULL); g_assert (severity_combo != NULL); g_assert (status_combo != NULL); g_assert (subject_entry != NULL); g_assert (fix_ver_combo != NULL); g_assert (descr_text != NULL); g_assert (fix_text != NULL); g_assert (change_log_text != NULL); g_assert (au_tr_text != NULL); client = g_object_get_data (G_OBJECT (widget), MY_GCONF_CLIENT); g_assert (client != NULL); conn = g_object_get_data (G_OBJECT (widget), MY_DB_CONN); g_assert (conn != NULL); pr_pk = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), PK_NUM)); g_assert (pr_pk != INVALID_PK); sql_buffer = g_string_new (""); /* * Check for submitter only access. */ if (submitter_access_only (conn, pr_pk)) { gtk_widget_set_sensitive (GTK_WIDGET (status_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (severity_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (fix_ver_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (responsible_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (fix_text), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (change_log_text), FALSE); } else { /* * Not submitter only, so apply a lock. */ if (!apply_lock (GTK_DIALOG (widget), conn, pr_pk)) { gtk_widget_set_sensitive (GTK_WIDGET (status_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (severity_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (fix_ver_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (responsible_combo), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (descr_text), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (fix_text), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (change_log_text), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (subject_entry), FALSE); } } /* * Start by querying back all of the data for the current problem report. * The results of this query will be stored in main_res for the duration * of the function call. * * Populate the widgets that can be populated directly. * * The combo widgets need to be populated with all of their possible * values before we can set their value. Thus, we set the value of * those widgets as we initialize their possible values. */ START_TRANSACTION (conn); { g_string_printf (sql_buffer, SELECT_PR_DATA, pr_pk); main_res = PQexec (conn, sql_buffer->str); if (chk_sql_error (main_res, "Populating PR Edit Dialog")) { g_assert (PQntuples (main_res) == 1); prj_pk = atoi (PQgetvalue (main_res, 0, PRJ_NUM_POS)); str = g_string_new (""); g_string_printf (str, _("Submitted By: %s"), PQgetvalue (main_res, 0, SUBMITTER_ID_POS)); gtk_label_set_markup (submitter_lbl, str->str); g_string_free (str, TRUE); gtk_entry_set_text (subject_entry, PQgetvalue (main_res, 0, TITLE_POS)); buff = gtk_text_view_get_buffer (descr_text); gtk_text_buffer_set_text (buff, PQgetvalue (main_res, 0, DESCR_POS), -1); gtk_text_buffer_set_modified (buff, FALSE); buff = gtk_text_view_get_buffer (fix_text); gtk_text_buffer_set_text (buff, PQgetvalue (main_res, 0, FIX_POS), -1); gtk_text_buffer_set_modified (buff, FALSE); txt_len = gtk_text_buffer_get_char_count (buff); lbl = GTK_LABEL (lookup_widget (widget, FIX_TAB_LBL)); g_assert (lbl != NULL); if (txt_len == 0) { gtk_label_set_text (lbl, FIX_DESCR); } else { gtk_label_set_text (lbl, FIX_DESCR_STAR); } g_object_set_data (G_OBJECT (widget), FIX_TAB_CHAR_CNT, GINT_TO_POINTER (txt_len)); buff = gtk_text_view_get_buffer (change_log_text); gtk_text_buffer_set_text (buff, PQgetvalue (main_res, 0, CHANGE_LOG_TEXT_POS), -1); gtk_text_buffer_set_modified (buff, FALSE); txt_len = gtk_text_buffer_get_char_count (buff); lbl = GTK_LABEL (lookup_widget (widget, CHGLOG_TAB_LBL)); g_assert (lbl != NULL); if (txt_len == 0) { gtk_label_set_text (lbl, CHGLOG_DESCR); } else { gtk_label_set_text (lbl, CHGLOG_DESCR_STAR); } g_object_set_data (G_OBJECT (widget), CHGLOG_TAB_CHAR_CNT, GINT_TO_POINTER (txt_len)); draw_audit_trail (au_tr_text, conn, pr_pk); } else { in_error = TRUE; } } if (!in_error) { targ_pk = atoi (PQgetvalue (main_res, 0, STATUS_NUM_POS)); init_attr_combo (status_combo, STAT_ATTR, client, conn, pr_pk, targ_pk); targ_pk = atoi (PQgetvalue (main_res, 0, SEVERITY_NUM_POS)); init_attr_combo (severity_combo, SEVR_ATTR, client, conn, pr_pk, targ_pk); targ_pk = atoi (PQgetvalue (main_res, 0, PROB_TYPE_POS)); init_attr_combo (prbtype_combo, PR_TYPE_ATTR, client, conn, pr_pk, targ_pk); gtk_widget_set_sensitive (GTK_WIDGET (prbtype_combo), FALSE); resp_id = g_string_new (PQgetvalue (main_res, 0, RESPONSIBLE_ID_POS)); init_assignee_combo (responsible_combo, conn, prj_pk, resp_id->str); g_string_free (resp_id, TRUE); init_prj_combo (project_combo, client, conn, prj_pk, pr_pk); gtk_widget_set_sensitive (GTK_WIDGET (project_combo), FALSE); pk = atoi (PQgetvalue (main_res, 0, OPEN_VER_POS)); init_prj_ver_combo (version_combo, conn, prj_pk, pk); gtk_widget_set_sensitive (GTK_WIDGET (version_combo), FALSE); if (PQgetisnull (main_res, 0, FIX_VER_POS)) { pk = 0; } else { pk = atoi (PQgetvalue (main_res, 0, FIX_VER_POS)); } init_prj_ver_combo (fix_ver_combo, conn, prj_pk, pk); } /* * TODO: Figure out what I wanted to do here, and do it. * * If the current user is in the submitter list, make the description * editable. If the current user is in the reponsible list, make the * responsible list pickable and the fix description editable. */ /* * If an error occurred along the way, destroy the dialog box. */ if (in_error) { ROLLBACK (conn); gtk_widget_destroy (widget); } else { COMMIT (conn); set_all_clean (G_OBJECT (widget)); gtk_dialog_set_response_sensitive (GTK_DIALOG (widget), GTK_RESPONSE_OK, FALSE); gtk_dialog_set_response_sensitive (GTK_DIALOG (widget), GTK_RESPONSE_APPLY, FALSE); } if (main_res != NULL) { PQclear (main_res); } g_string_free (sql_buffer, TRUE); } static void on_pr_dlg_destroy (GObject *object, gpointer user_data) { GtkWidget *main_widget; GtkWidget *widget; GList *temp_list; GList *list_iter; PGconn *conn; gint pk_num; main_widget = GTK_WIDGET (object); conn = g_object_get_data (G_OBJECT (main_widget), MY_DB_CONN); g_assert (conn != NULL); pk_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_widget), PK_NUM)); remove_lock (conn, pk_num); /* * Free up the ID lists that are attached to the option menus. */ widget = lookup_widget (main_widget, RESPONSIBLE_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); for (list_iter = g_list_first (temp_list); list_iter != NULL; list_iter = list_iter->next) { g_string_free ((GString *)list_iter->data, TRUE); } g_list_free (temp_list); widget = lookup_widget (main_widget, SEVERITY_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); g_list_free (temp_list); widget = lookup_widget (main_widget, STATUS_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); g_list_free (temp_list); widget = lookup_widget (main_widget, FIX_VER_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); g_list_free (temp_list); widget = lookup_widget (widget, PROJECT_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); g_list_free (temp_list); widget = lookup_widget (widget, VERSION_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); g_list_free (temp_list); widget = lookup_widget (widget, PRBTYPE_COMBO); g_assert (widget != NULL); temp_list = g_object_get_data (G_OBJECT (widget), PK_LIST); g_list_free (temp_list); temp_list = g_object_get_data (G_OBJECT (widget), DEF_SEVR_LIST); g_list_free (temp_list); destroy_dirty_list (G_OBJECT (main_widget)); } /*-------------------------------------------------------------------------- * Button Clicked Handlers *-------------------------------------------------------------------------- */ static void append_sql_update (GString *sql, const gchar *colname, const gchar *value, gboolean first) { if (first) { sql = g_string_assign (sql, "UPDATE PROBLEM_REPORT SET "); } else { sql = g_string_append (sql, ", "); } g_string_append_printf (sql, "%s = %s ", colname, value); } static void append_sql_insert (GString *ins_sql, GString *val_sql, const gchar *colname, const gchar *value, gboolean first) { if (first) { ins_sql = g_string_assign (ins_sql, "INSERT INTO PROBLEM_REPORT ("); val_sql = g_string_assign (val_sql, "VALUES ("); } else { ins_sql = g_string_append (ins_sql, ", "); val_sql = g_string_append (val_sql, ", "); } ins_sql = g_string_append (ins_sql, colname); val_sql = g_string_append (val_sql, value); } static void convert_to_update_mode (GtkWidget *dlg) { GtkLabel *lbl; GtkWidget *widget; gint pk_num; GString *title; /* * First, change a couple of titles from "New" to include the * problem report number. */ lbl = GTK_LABEL (lookup_widget (dlg, TITLE_LABEL)); g_assert (lbl != NULL); pk_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dlg), PK_NUM)); g_assert (pk_num != 0); title = g_string_new (""); g_string_printf (title, TITLE_STRING, pk_num); gtk_label_set_text (lbl, title->str); gtk_window_set_title (GTK_WINDOW (dlg), title->str); g_string_free (title, TRUE); /* * Now disable a couple of widgets for data that is not changable * when in update mode. */ widget = lookup_widget (dlg, PROJECT_COMBO); g_assert (widget != NULL); gtk_widget_set_sensitive (widget, FALSE); widget = lookup_widget (dlg, VERSION_COMBO); g_assert (widget != NULL); gtk_widget_set_sensitive (widget, FALSE); widget = lookup_widget (dlg, PRBTYPE_COMBO); g_assert (widget != NULL); gtk_widget_set_sensitive (widget, FALSE); } static gboolean apply_changes (GtkDialog *dlg) { GtkWidget *main_widget; GtkWidget *parent; /* main application window */ GtkEntry *subject_entry; #ifdef USE_NEW_GTK GtkComboBox *responsible_combo; GtkComboBox *status_combo; GtkComboBox *severity_combo; GtkComboBox *fix_ver_combo; GtkComboBox *pr_type_combo; GtkComboBox *project_combo; GtkComboBox *version_combo; #else GtkOptionMenu *responsible_combo; GtkOptionMenu *status_combo; GtkOptionMenu *severity_combo; GtkOptionMenu *fix_ver_combo; GtkOptionMenu *pr_type_combo; GtkOptionMenu *project_combo; GtkOptionMenu *version_combo; #endif gint sel; GtkTextView *descr_text; GtkTextView *fix_text; GtkTextView *change_log_text; GtkTextBuffer *buff; GtkTextIter start; GtkTextIter end; GList *pk_list; GList *list_iter; GString *tmp_str; GString *sql_buffer; GString *val_buffer = NULL; PGresult *res; gboolean in_error = FALSE; gboolean first = TRUE; gchar num_buffer[NUM_BUFFER_LEN]; gchar *char_buf; PGconn *conn; gint pk_num; /* the pk_num of the problem report */ gint pk; /* temporary PK used while building DML */ GtkWidget *msg_dlg; gboolean insert; main_widget = GTK_WIDGET (dlg); conn = g_object_get_data (G_OBJECT (main_widget), MY_DB_CONN); g_assert (conn != NULL); pk_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_widget), PK_NUM)); parent = lookup_widget (main_widget, MY_PARENT); /* * Get pointers to all the widgets we will need to access. */ subject_entry = GTK_ENTRY (lookup_widget (main_widget, SUBJECT_ENTRY)); #ifdef USE_NEW_GTK responsible_combo = GTK_COMBO_BOX (lookup_widget (main_widget, RESPONSIBLE_COMBO)); status_combo = GTK_COMBO_BOX (lookup_widget (main_widget, STATUS_COMBO)); severity_combo = GTK_COMBO_BOX (lookup_widget (main_widget, SEVERITY_COMBO)); fix_ver_combo = GTK_COMBO_BOX (lookup_widget (main_widget, FIX_VER_COMBO)); pr_type_combo = GTK_COMBO_BOX (lookup_widget (main_widget, PRBTYPE_COMBO)); project_combo = GTK_COMBO_BOX (lookup_widget (main_widget, PROJECT_COMBO)); version_combo = GTK_COMBO_BOX (lookup_widget (main_widget, VERSION_COMBO)); #else responsible_combo = GTK_OPTION_MENU (lookup_widget (main_widget, RESPONSIBLE_COMBO)); status_combo = GTK_OPTION_MENU (lookup_widget (main_widget, STATUS_COMBO)); severity_combo = GTK_OPTION_MENU (lookup_widget (main_widget, SEVERITY_COMBO)); fix_ver_combo = GTK_OPTION_MENU (lookup_widget (main_widget, FIX_VER_COMBO)); pr_type_combo = GTK_OPTION_MENU (lookup_widget (main_widget, PRBTYPE_COMBO)); project_combo = GTK_OPTION_MENU (lookup_widget (main_widget, PROJECT_COMBO)); version_combo = GTK_OPTION_MENU (lookup_widget (main_widget, VERSION_COMBO)); #endif descr_text = GTK_TEXT_VIEW (lookup_widget (main_widget, DESCR_EDIT)); fix_text = GTK_TEXT_VIEW (lookup_widget (main_widget, FIX_DESCR_EDIT)); change_log_text = GTK_TEXT_VIEW (lookup_widget (main_widget, CHANGE_LOG_TEXT)); /* * Determine if this is INSERT or UPDATE mode. This can be determined * from the pk_num. If the pk_num is INVALID_PK, the dialog is in * INSERT mode. Otherwise, the dialog is in UPDATE mode. */ insert = (pk_num == INVALID_PK); /* * If the user is doing an insert operation or if the dialog has dirty * widgets, round up all of the information that we will need. * * Do validations as needed. */ if (insert || problem_update_dlg_dirty (main_widget)) { /* * Start the DML. */ sql_buffer = g_string_new (""); tmp_str = g_string_new (""); if (insert) { val_buffer = g_string_new (""); append_sql_insert (sql_buffer, val_buffer, "archived", "false", first); first = FALSE; } /* * For each item, append the data. For inserts, append them * all. For updates, only append the dirty items. */ if (!in_error && (insert || object_is_dirty (G_OBJECT (project_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (project_combo); #else sel = gtk_option_menu_get_history (project_combo); #endif pk_list = g_object_get_data (G_OBJECT (project_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); g_string_printf (tmp_str, "%d", GPOINTER_TO_INT (list_iter->data)); if (insert) { append_sql_insert (sql_buffer, val_buffer, "project_num", tmp_str->str, first); } else { append_sql_update (sql_buffer, "project_num", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (version_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (version_combo); #else sel = gtk_option_menu_get_history (version_combo); #endif pk_list = g_object_get_data (G_OBJECT (version_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); if (GPOINTER_TO_INT (list_iter->data) == INVALID_PK) { tmp_str = g_string_assign (tmp_str, "NULL"); } else { g_string_printf (tmp_str, "%d", GPOINTER_TO_INT (list_iter->data)); } if (insert) { append_sql_insert (sql_buffer, val_buffer, "open_version", tmp_str->str, first); } else { append_sql_update (sql_buffer, "open_version", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (responsible_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (responsible_combo); #else sel = gtk_option_menu_get_history (responsible_combo); #endif pk_list = g_object_get_data (G_OBJECT (responsible_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); tmp_str = g_string_assign (tmp_str, ((GString*)list_iter->data)->str); g_string_prepare_db_instr (tmp_str); if (insert) { append_sql_insert (sql_buffer, val_buffer, "responsible_id", tmp_str->str, first); } else { append_sql_update (sql_buffer, "responsible_id", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (subject_entry)))) { tmp_str = g_string_assign (tmp_str, gtk_entry_get_text (subject_entry)); g_string_prepare_db_instr (tmp_str); /* * Subtract 2 to compensate for single quotes added for the * update statement. */ if (tmp_str->len - 2 < MIN_SUBJECT_LEN || (MIN_SUBJECT_LEN > 0 && !strcmp (tmp_str->str, "NULL"))) { GString *msg_str; msg_str = g_string_new (""); g_string_printf (msg_str, _("You must enter at least %d character(s) in the subject"), MIN_SUBJECT_LEN); msg_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (msg_dlg)); gtk_widget_destroy (msg_dlg); g_string_free (msg_str, TRUE); in_error = TRUE; } else { if (insert) { append_sql_insert (sql_buffer, val_buffer, "title", tmp_str->str, first); } else { append_sql_update (sql_buffer, "title", tmp_str->str, first); } first = FALSE; } } buff = gtk_text_view_get_buffer (descr_text); if (!in_error && (insert || gtk_text_buffer_get_modified (buff))) { gtk_text_buffer_get_bounds (buff, &start, &end); char_buf = gtk_text_buffer_get_text (buff, &start, &end, FALSE); tmp_str = g_string_assign (tmp_str, char_buf); g_free (char_buf); g_string_prepare_db_instr (tmp_str); /* * Subtract 2 to compensate for single quotes added for the * update statement. */ if (tmp_str->len - 2 < MIN_DESCR_LEN || (MIN_DESCR_LEN > 0 && !strcmp (tmp_str->str, "NULL"))) { GString *msg_str; msg_str = g_string_new (""); g_string_printf (msg_str, _("You must enter at least %d character(s) in the description"), MIN_DESCR_LEN); msg_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (msg_dlg)); gtk_widget_destroy (msg_dlg); g_string_free (msg_str, TRUE); in_error = TRUE; } else { if (insert) { append_sql_insert (sql_buffer, val_buffer, "descr", tmp_str->str, first); } else { append_sql_update (sql_buffer, "descr", tmp_str->str, first); } first = FALSE; } } buff = gtk_text_view_get_buffer (fix_text); if (!in_error && (insert || gtk_text_buffer_get_modified (buff))) { gtk_text_buffer_get_bounds (buff, &start, &end); char_buf = gtk_text_buffer_get_text (buff, &start, &end, FALSE); tmp_str = g_string_assign (tmp_str, char_buf); g_free (char_buf); g_string_prepare_db_instr (tmp_str); if (insert) { append_sql_insert (sql_buffer, val_buffer, "fix", tmp_str->str, first); } else { append_sql_update (sql_buffer, "fix", tmp_str->str, first); } first = FALSE; } buff = gtk_text_view_get_buffer (change_log_text); if (!in_error && (insert || gtk_text_buffer_get_modified (buff))) { gtk_text_buffer_get_bounds (buff, &start, &end); char_buf = gtk_text_buffer_get_text (buff, &start, &end, FALSE); tmp_str = g_string_assign (tmp_str, char_buf); g_free (char_buf); g_string_prepare_db_instr (tmp_str); if (insert) { append_sql_insert (sql_buffer, val_buffer, "change_log_text", tmp_str->str, first); } else { append_sql_update (sql_buffer, "change_log_text", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (fix_ver_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (fix_ver_combo); #else sel = gtk_option_menu_get_history (fix_ver_combo); #endif pk_list = g_object_get_data (G_OBJECT (fix_ver_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); pk = GPOINTER_TO_INT (list_iter->data); if (pk == INVALID_PK) { tmp_str = g_string_assign (tmp_str, "NULL"); } else { g_string_printf (tmp_str, "%d", pk); } if (insert) { append_sql_insert (sql_buffer, val_buffer, "close_version", tmp_str->str, first); } else { append_sql_update (sql_buffer, "close_version", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (pr_type_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (pr_type_combo); #else sel = gtk_option_menu_get_history (pr_type_combo); #endif pk_list = g_object_get_data (G_OBJECT (pr_type_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); pk = GPOINTER_TO_INT (list_iter->data); if (pk == INVALID_PK) { tmp_str = g_string_assign (tmp_str, "NULL"); } else { g_string_printf (tmp_str, "%d", pk); } if (insert) { append_sql_insert (sql_buffer, val_buffer, "type_num", tmp_str->str, first); } else { append_sql_update (sql_buffer, "type_num", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (status_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (status_combo); #else sel = gtk_option_menu_get_history (status_combo); #endif pk_list = g_object_get_data (G_OBJECT (status_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); pk = GPOINTER_TO_INT (list_iter->data); if (pk == INVALID_PK) { tmp_str = g_string_assign (tmp_str, "NULL"); } else { g_string_printf (tmp_str, "%d", pk); } if (insert) { append_sql_insert (sql_buffer, val_buffer, "status_num", tmp_str->str, first); } else { append_sql_update (sql_buffer, "status_num", tmp_str->str, first); } first = FALSE; } if (!in_error && (insert || object_is_dirty (G_OBJECT (severity_combo)))) { #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (severity_combo); #else sel = gtk_option_menu_get_history (severity_combo); #endif pk_list = g_object_get_data (G_OBJECT (severity_combo), PK_LIST); list_iter = g_list_nth (pk_list, sel); pk = GPOINTER_TO_INT (list_iter->data); if (pk == INVALID_PK) { tmp_str = g_string_assign (tmp_str, "NULL"); } else { g_string_printf (tmp_str, "%d", pk); } if (insert) { append_sql_insert (sql_buffer, val_buffer, "severity_num", tmp_str->str, first); } else { append_sql_update (sql_buffer, "severity_num", tmp_str->str, first); } first = FALSE; } /* * Update the database. */ if (!in_error) { g_assert (!first); if (insert) { append_sql_insert (sql_buffer, val_buffer, "submitter_id", "getpgusername()", FALSE); START_TRANSACTION (conn); res = PQexec (conn, "select nextval ('problem_report_seq')"); in_error = !chk_sql_error (res, "Get pk_num"); g_assert (PQntuples (res) == 1); if (!in_error) { pk_num = atoi (PQgetvalue (res, 0, 0)); sql_buffer = g_string_append (sql_buffer, ", problem_num)"); g_string_append_printf (val_buffer, ", %d)", pk_num); sql_buffer = g_string_append (sql_buffer, val_buffer->str); PQclear (res); res = PQexec (conn, sql_buffer->str); in_error = !chk_sql_error (res, "Insert Problem Report"); if (!in_error) { set_all_clean (G_OBJECT (dlg)); refresh_pr_list (parent); g_object_set_data (G_OBJECT (main_widget), PK_NUM, GINT_TO_POINTER (pk_num)); convert_to_update_mode (main_widget); } } finalize_transaction (conn, res); PQclear (res); } else { /* * If we are here, their ought to be at least one thing that * we are updating... */ START_TRANSACTION (conn); sprintf (num_buffer, "%d", pk_num); sql_buffer = g_string_append (sql_buffer, " WHERE problem_num = "); sql_buffer = g_string_append (sql_buffer, num_buffer); res = PQexec (conn, sql_buffer->str); in_error = !chk_sql_error (res, "Updating Problem Report"); if (!in_error) { set_all_clean (G_OBJECT (dlg)); refresh_pr_list (parent); } finalize_transaction (conn, res); PQclear (res); } } g_string_free (sql_buffer, TRUE); g_string_free (tmp_str, TRUE); if (val_buffer != NULL) { g_string_free (val_buffer, TRUE); val_buffer = NULL; } } return !in_error; } static void on_ok_button_clicked (GtkDialog *dlg) { GConfClient *client; client = g_object_get_data (G_OBJECT (dlg), MY_GCONF_CLIENT); g_assert (client != NULL); if (apply_changes (dlg)) { save_dlg_size (client, GTK_WIDGET (dlg), PROB_UPD_SEC); gtk_widget_destroy (GTK_WIDGET (dlg)); } } static void on_apply_button_clicked (GtkDialog *dlg) { if (apply_changes (dlg)) { gtk_dialog_set_response_sensitive (dlg, GTK_RESPONSE_APPLY, FALSE); gtk_dialog_set_response_sensitive (dlg, GTK_RESPONSE_OK, FALSE); } } static void on_cancel_button_clicked (GtkDialog *dlg) { GConfClient *client; client = g_object_get_data (G_OBJECT (dlg), MY_GCONF_CLIENT); g_assert (client != NULL); save_dlg_size (client, GTK_WIDGET (dlg), PROB_UPD_SEC); gtk_widget_destroy (GTK_WIDGET (dlg)); } static void on_pr_dlg_clicked (GtkDialog *dlg, gint btn_cd, gpointer user_data) { static gboolean processing = FALSE; if (!processing) { processing = TRUE; switch (btn_cd) { case GTK_RESPONSE_OK: on_ok_button_clicked (dlg); break; case GTK_RESPONSE_APPLY: on_apply_button_clicked (dlg); break; case GTK_RESPONSE_CANCEL: on_cancel_button_clicked (dlg); break; case GTK_RESPONSE_DELETE_EVENT: break; default: g_assert_not_reached (); } processing = FALSE; } } /*-------------------------------------------------------------------------- * Widget Changed handlers *-------------------------------------------------------------------------- */ static gboolean min_text_entered (GtkWidget *dlg) { GtkTextView *descr_text; GtkTextBuffer *buff; GtkTextIter start; GtkTextIter end; GtkEntry *subject_entry; GString *tmp_str; gboolean text_entered = TRUE; gchar *char_buf; descr_text = GTK_TEXT_VIEW (lookup_widget (dlg, DESCR_EDIT)); g_assert (descr_text != NULL); subject_entry = GTK_ENTRY (lookup_widget (dlg, SUBJECT_ENTRY)); g_assert (subject_entry != NULL); tmp_str = g_string_new (gtk_entry_get_text (subject_entry)); tmp_str = g_string_strip (tmp_str); text_entered = text_entered && (tmp_str->len >= MIN_SUBJECT_LEN); buff = gtk_text_view_get_buffer (descr_text); gtk_text_buffer_get_bounds (buff, &start, &end); char_buf = gtk_text_buffer_get_text (buff, &start, &end, FALSE); tmp_str = g_string_assign (tmp_str, char_buf); g_free (char_buf); tmp_str = g_string_strip (tmp_str); text_entered = text_entered && (tmp_str->len >= MIN_DESCR_LEN); g_string_free (tmp_str, TRUE); return text_entered; } static void check_chglog_tab_text (GtkTextBuffer *buff, gpointer user_data) { GtkWidget *main_win = GTK_WIDGET (user_data); GtkLabel *tab_lbl; gint curr_len; gint stored_len; tab_lbl = GTK_LABEL (lookup_widget (main_win, CHGLOG_TAB_LBL)); g_assert (tab_lbl != NULL); curr_len = gtk_text_buffer_get_char_count (buff); if (curr_len == 0) { gtk_label_set_text (tab_lbl, CHGLOG_DESCR); } else { /* * Each time these things change, the current len is stored in * CHGLOG_TAB_CHAR_CNT. We only want to change to a '*' if the * last time we did not have any chars, and now we do... */ stored_len = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_win), CHGLOG_TAB_CHAR_CNT)); if (!stored_len) { gtk_label_set_text (tab_lbl, CHGLOG_DESCR_STAR); } } g_object_set_data (G_OBJECT (main_win), CHGLOG_TAB_CHAR_CNT, GINT_TO_POINTER (curr_len)); } static void check_fix_tab_text (GtkTextBuffer *buff, gpointer user_data) { GtkWidget *main_win = GTK_WIDGET (user_data); GtkLabel *tab_lbl; gint curr_len; gint stored_len; tab_lbl = GTK_LABEL (lookup_widget (main_win, FIX_TAB_LBL)); g_assert (tab_lbl != NULL); curr_len = gtk_text_buffer_get_char_count (buff); if (curr_len == 0) { gtk_label_set_text (tab_lbl, FIX_DESCR); } else { /* * Each time these things change, the current len is stored in * FIX_TAB_CHAR_CNT. We only want to change to a '*' if the * last time we did not have any chars, and now we do... */ stored_len = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (main_win), FIX_TAB_CHAR_CNT)); if (!stored_len) { gtk_label_set_text (tab_lbl, FIX_DESCR_STAR); } } g_object_set_data (G_OBJECT (main_win), FIX_TAB_CHAR_CNT, GINT_TO_POINTER (curr_len)); } static void on_text_buffer_changed (GtkTextBuffer *buff, gpointer user_data) { if (min_text_entered (GTK_WIDGET (user_data))) { gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, TRUE); gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_APPLY, TRUE); } else { gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, FALSE); gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_APPLY, FALSE); } } static void handle_widget_change (GtkWidget *widget, gpointer user_data) { set_dirty (G_OBJECT (widget), NULL); if (min_text_entered (GTK_WIDGET (user_data))) { gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, TRUE); gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_APPLY, TRUE); } else { gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, FALSE); gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_APPLY, FALSE); } } gboolean problem_update_dlg_dirty (GtkWidget *dlg) { GtkTextView *view; GtkTextBuffer *buff; /* * First check the text view widgets, then check the list of other * widgets that can make the dialog dirty. */ view = GTK_TEXT_VIEW (lookup_widget (dlg, DESCR_EDIT)); g_assert (view != NULL); buff = gtk_text_view_get_buffer (view); if (gtk_text_buffer_get_modified (buff)) { return TRUE; } view = GTK_TEXT_VIEW (lookup_widget (dlg, FIX_DESCR_EDIT)); g_assert (view != NULL); buff = gtk_text_view_get_buffer (view); if (gtk_text_buffer_get_modified (buff)) { return TRUE; } view = GTK_TEXT_VIEW (lookup_widget (dlg, CHANGE_LOG_TEXT)); g_assert (view != NULL); buff = gtk_text_view_get_buffer (view); if (gtk_text_buffer_get_modified (buff)) { return TRUE; } return objects_children_are_dirty (G_OBJECT (dlg)); } static void set_default_severity (GtkWidget *pt_combo, GtkWidget *dlg) { GtkWidget *sevr_combo; GList *sevrs; GList *def_sevr; GList *iter; PGconn *conn; gint sel; gint pr_pk; /* * This stuff is only done if we are in INSERT mode, which is detected * by the not having a valid PK. */ pr_pk = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dlg), PK_NUM)); if (pr_pk == INVALID_PK) { sevr_combo = lookup_widget (dlg, SEVERITY_COMBO); g_assert (sevr_combo != NULL); conn = g_object_get_data (G_OBJECT (dlg), MY_DB_CONN); g_assert (conn != NULL); def_sevr = g_object_get_data (G_OBJECT (pt_combo), DEF_SEVR_LIST); g_assert (def_sevr != NULL); #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (GTK_COMBO_BOX (pt_combo)); #else sel = gtk_option_menu_get_history (GTK_OPTION_MENU (pt_combo)); #endif def_sevr = g_list_nth (def_sevr, sel); g_assert (def_sevr != NULL); sevrs = g_object_get_data (G_OBJECT (sevr_combo), PK_LIST); sel = 0; for (iter = g_list_first (sevrs); iter != NULL; iter = iter->next) { if (iter->data == def_sevr->data) { break; } sel++; } g_assert (iter != NULL); #ifdef USE_NEW_GTK gtk_combo_box_set_active (GTK_COMBO_BOX (sevr_combo), sel); #else gtk_option_menu_set_history (GTK_OPTION_MENU (sevr_combo), sel); #endif } } static void on_project_changed (GtkWidget *prj_combo, GtkWidget *dlg) { GList *pk_list; gint sel; gint prj_num; gint ver_num; #ifdef USE_NEW_GTK GtkComboBox *version_combo; GtkComboBox *fix_ver_combo; GtkComboBox *responsible_combo; #else GtkOptionMenu *version_combo; GtkOptionMenu *fix_ver_combo; GtkOptionMenu *responsible_combo; #endif PGconn *conn; conn = g_object_get_data (G_OBJECT (dlg), MY_DB_CONN); g_assert (conn != NULL); #ifdef USE_NEW_GTK responsible_combo = GTK_COMBO_BOX (lookup_widget (dlg, RESPONSIBLE_COMBO)); g_assert (responsible_combo != NULL); version_combo = GTK_COMBO_BOX (lookup_widget (dlg, VERSION_COMBO)); g_assert (version_combo != NULL); fix_ver_combo = GTK_COMBO_BOX (lookup_widget (dlg, FIX_VER_COMBO)); g_assert (fix_ver_combo != NULL); sel = gtk_combo_box_get_active (GTK_COMBO_BOX (prj_combo)); #else responsible_combo = GTK_OPTION_MENU (lookup_widget (dlg, RESPONSIBLE_COMBO)); g_assert (responsible_combo != NULL); version_combo = GTK_OPTION_MENU (lookup_widget (dlg, VERSION_COMBO)); g_assert (version_combo != NULL); fix_ver_combo = GTK_OPTION_MENU (lookup_widget (dlg, FIX_VER_COMBO)); g_assert (fix_ver_combo != NULL); sel = gtk_option_menu_get_history (GTK_OPTION_MENU (prj_combo)); #endif pk_list = g_object_get_data (G_OBJECT (prj_combo), PK_LIST); pk_list = g_list_nth (pk_list, sel); prj_num = GPOINTER_TO_INT (pk_list->data); pk_list = g_object_get_data (G_OBJECT (prj_combo), DEF_OPEN_VER_LIST); pk_list = g_list_nth (pk_list, sel); ver_num = GPOINTER_TO_INT (pk_list->data); init_prj_ver_combo (version_combo, conn, prj_num, ver_num); init_prj_ver_combo (fix_ver_combo, conn, prj_num, INVALID_PK); init_assignee_combo (responsible_combo, conn, prj_num, NULL); } static void reset_def_ver (GtkWidget *prj_ver_combo, GtkWidget *dlg) { #ifdef USE_NEW_GTK GtkComboBox *project_combo; #else GtkOptionMenu *project_combo; #endif gint sel; GList *pk_list; gint ver_num; #ifdef USE_NEW_GTK sel = gtk_combo_box_get_active (GTK_COMBO_BOX (prj_ver_combo)); #else sel = gtk_option_menu_get_history (GTK_OPTION_MENU (prj_ver_combo)); #endif pk_list = g_object_get_data (G_OBJECT (prj_ver_combo), PK_LIST); pk_list = g_list_nth (pk_list, sel); ver_num = GPOINTER_TO_INT (pk_list->data); #ifdef USE_NEW_GTK project_combo = GTK_COMBO_BOX (lookup_widget (dlg, PROJECT_COMBO)); g_assert (project_combo != NULL); sel = gtk_combo_box_get_active (project_combo); #else project_combo = GTK_OPTION_MENU (lookup_widget (dlg, PROJECT_COMBO)); g_assert (project_combo != NULL); sel = gtk_option_menu_get_history (project_combo); #endif pk_list = g_object_get_data (G_OBJECT (project_combo), DEF_OPEN_VER_LIST); pk_list = g_list_nth (pk_list, sel); pk_list->data = GINT_TO_POINTER (ver_num); } /*-------------------------------------------------------------------------- * Externally visable functions. *-------------------------------------------------------------------------- */ GtkWidget * create_problem_update_dlg (GtkWidget *parent, PGconn *conn, gint pr_pk) { GtkWidget *pr_update_dlg; GConfClient *client; GString *window_title; GString *static_title; GtkWidget *dialog_vbox; GtkWidget *vbox; GtkWidget *dtl_vbox; GtkWidget *dtl_hbox; GtkWidget *label; GtkWidget *notebook; GtkWidget *descr_scroll; GtkWidget *descr_text; GtkWidget *fix_scroll; GtkWidget *fix_text; GtkWidget *change_log_scroll; GtkWidget *change_log_text; GtkWidget *audit_trail_scroll; GtkWidget *audit_trail_text; GtkWidget *assign_combo; GtkWidget *status_combo; GtkWidget *severity_combo; GtkWidget *version_combo; GtkWidget *project_combo; GtkWidget *prbtype_combo; GtkWidget *fixver_combo; GtkWidget *subject_entry; GtkSizeGroup *size_group; GtkTextBuffer *buff; gboolean updating; gulong id; client = g_object_get_data (G_OBJECT (parent), MY_GCONF_CLIENT); g_assert (client != NULL); /* * The PK of INVALID_PK shall be used throughout to signify that * this is a new problem report. */ updating = (pr_pk != INVALID_PK); window_title = g_string_new (""); if (updating) { g_string_printf (window_title, TITLE_STRING, pr_pk); } else { g_string_printf (window_title, _("New Problem Report")); } pr_update_dlg = gtk_dialog_new_with_buttons (window_title->str, NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_OK, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); GLADE_HOOKUP_OBJECT_NO_REF (pr_update_dlg, pr_update_dlg, "pr_update_dlg"); gtk_container_set_border_width (GTK_CONTAINER (pr_update_dlg), STD_DLG_BORDER); if (updating) { g_signal_connect (pr_update_dlg, "show", G_CALLBACK (on_pr_dlg_show_for_updpr), NULL); } else { g_signal_connect (pr_update_dlg, "show", G_CALLBACK (on_pr_dlg_show_for_newpr), NULL); } g_signal_connect (pr_update_dlg, "destroy", G_CALLBACK (on_pr_dlg_destroy), NULL); g_signal_connect (pr_update_dlg, "response", G_CALLBACK (on_pr_dlg_clicked), NULL); gtk_window_set_resizable (GTK_WINDOW (pr_update_dlg), TRUE); gtk_dialog_set_default_response (GTK_DIALOG (pr_update_dlg), GTK_RESPONSE_OK); g_object_set_data (G_OBJECT (pr_update_dlg), TOP_DOG, pr_update_dlg); g_object_set_data (G_OBJECT (pr_update_dlg), MY_PARENT, parent); g_object_set_data (G_OBJECT (pr_update_dlg), MY_DB_CONN, conn); g_object_set_data (G_OBJECT (pr_update_dlg), MY_GCONF_CLIENT, client); g_object_set_data (G_OBJECT (pr_update_dlg), PK_NUM, GINT_TO_POINTER (pr_pk)); set_dlg_size (client, pr_update_dlg, PROB_UPD_SEC, 625, 500); /*---------------------------------------------------------------------- * General layout: * dialog_vbox * vbox -- One for each basic section, provides separation * dtl_vbox -- contains a dtl_hbox for each item in section * dtl_hbox * dtl_hbox * ... * vbox * dtl_vbox * dtl_hbox * dtl_hbox * ... * ... *--------------------------------------------------------------------*/ dialog_vbox = GTK_DIALOG (pr_update_dlg)->vbox; GLADE_HOOKUP_OBJECT (pr_update_dlg, dialog_vbox, "dialog_vbox"); gtk_box_set_spacing (GTK_BOX (dialog_vbox), MAIN_VBOX_SPACING); size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); /*---------------------------------------------------------------------- * The first set of labels is not indented. Thus, we do not have * * *--------------------------------------------------------------------*/ vbox = gtk_vbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, vbox, "statictxtvbox"); gtk_box_pack_start (GTK_BOX (dialog_vbox), vbox, FALSE, FALSE, 0); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "subhbox"); gtk_box_pack_start (GTK_BOX (vbox), dtl_hbox, FALSE, FALSE, 0); static_title = g_string_new (""); g_string_append_printf (static_title, "%s", window_title->str); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), static_title->str); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, TITLE_LABEL); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); g_string_free (static_title, TRUE); g_string_free (window_title, TRUE); label = gtk_label_new (NULL); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, SUBMTTR_LABEL); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); dtl_vbox = gtk_vbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_vbox, "dtlvbox1"); gtk_box_pack_start (GTK_BOX (vbox), dtl_vbox, TRUE, TRUE, 0); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "subjecthbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (_("Subject:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "subjectlbl"); gtk_size_group_add_widget (size_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); subject_entry = gtk_entry_new (); GLADE_HOOKUP_OBJECT (pr_update_dlg, subject_entry, SUBJECT_ENTRY); gtk_box_pack_start (GTK_BOX (dtl_hbox), subject_entry, TRUE, TRUE, 0); g_signal_connect (subject_entry, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (subject_entry)); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "prjhbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), _("Project:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "prjlbl"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_size_group_add_widget (size_group, label); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); #ifdef USE_NEW_GTK project_combo = gtk_combo_box_new_text (); #else project_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, project_combo, PROJECT_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), project_combo, TRUE, TRUE, 0); g_signal_connect (project_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (project_combo)); #ifdef USE_NEW_GTK version_combo = gtk_combo_box_new_text (); #else version_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, version_combo, VERSION_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), version_combo, FALSE, FALSE, 0); g_signal_connect (version_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); /* * We need to turn this signal handler off while we (re)build the * version combo. Thus, we save its ID. */ id = g_signal_connect (version_combo, "changed", G_CALLBACK (reset_def_ver), pr_update_dlg); g_object_set_data (G_OBJECT (version_combo), RESET_DEF_VER_ID, GINT_TO_POINTER (id)); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (version_combo)); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "pthbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), _("Problem Type:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "ptlbl"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_size_group_add_widget (size_group, label); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); #ifdef USE_NEW_GTK prbtype_combo = gtk_combo_box_new_text (); #else prbtype_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, prbtype_combo, PRBTYPE_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), prbtype_combo, TRUE, TRUE, 0); g_signal_connect (prbtype_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (prbtype_combo)); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "sevrhbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (_("Severity:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "sevrlbl"); gtk_size_group_add_widget (size_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); #ifdef USE_NEW_GTK severity_combo = gtk_combo_box_new_text (); #else severity_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, severity_combo, SEVERITY_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), severity_combo, TRUE, TRUE, 0); g_signal_connect (severity_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (severity_combo)); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "stathbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (_("Status:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "statlbl"); gtk_size_group_add_widget (size_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); #ifdef USE_NEW_GTK status_combo = gtk_combo_box_new_text (); #else status_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, status_combo, STATUS_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), status_combo, TRUE, TRUE, 0); g_signal_connect (status_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (status_combo)); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "asstohbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (_("Assigned To:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "asstolbl"); gtk_size_group_add_widget (size_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); #ifdef USE_NEW_GTK assign_combo = gtk_combo_box_new_text (); #else assign_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, assign_combo, RESPONSIBLE_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), assign_combo, TRUE, TRUE, 0); g_signal_connect (assign_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (assign_combo)); dtl_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (pr_update_dlg, dtl_hbox, "targverhbox"); gtk_box_pack_start (GTK_BOX (dtl_vbox), dtl_hbox, FALSE, FALSE, 0); label = gtk_label_new (_("Target Version:")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "targverlbl"); gtk_size_group_add_widget (size_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (dtl_hbox), label, FALSE, FALSE, 0); #ifdef USE_NEW_GTK fixver_combo = gtk_combo_box_new_text (); #else fixver_combo = gtk_option_menu_new (); #endif GLADE_HOOKUP_OBJECT (pr_update_dlg, fixver_combo, FIX_VER_COMBO); gtk_box_pack_start (GTK_BOX (dtl_hbox), fixver_combo, TRUE, TRUE, 0); g_signal_connect (fixver_combo, "changed", G_CALLBACK (handle_widget_change), pr_update_dlg); add_object_to_dirty_list (G_OBJECT (pr_update_dlg), G_OBJECT (fixver_combo)); /*---------------------------------------------------------------------- * Start the long descriptions (in tabbed windows). *--------------------------------------------------------------------*/ notebook = gtk_notebook_new (); GLADE_HOOKUP_OBJECT (pr_update_dlg, notebook, "notebook"); gtk_box_pack_start (GTK_BOX (dialog_vbox), notebook, TRUE, TRUE, 0); descr_scroll = gtk_scrolled_window_new (NULL, NULL); GLADE_HOOKUP_OBJECT (pr_update_dlg, descr_scroll, "descr_scroll"); gtk_container_add (GTK_CONTAINER (notebook), descr_scroll); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (descr_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (descr_scroll), GTK_SHADOW_ETCHED_IN); descr_text = gtk_text_view_new (); GLADE_HOOKUP_OBJECT (pr_update_dlg, descr_text, DESCR_EDIT); gtk_container_add (GTK_CONTAINER (descr_scroll), descr_text); gtk_widget_set_size_request (descr_text, -1, 150); gtk_text_view_set_editable (GTK_TEXT_VIEW (descr_text), TRUE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (descr_text), GTK_WRAP_WORD); buff = gtk_text_view_get_buffer (GTK_TEXT_VIEW (descr_text)); g_signal_connect (buff, "changed", G_CALLBACK (on_text_buffer_changed), pr_update_dlg); fix_scroll = gtk_scrolled_window_new (NULL, NULL); GLADE_HOOKUP_OBJECT (pr_update_dlg, fix_scroll, "fix_scroll"); gtk_container_add (GTK_CONTAINER (notebook), fix_scroll); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (fix_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (fix_scroll), GTK_SHADOW_ETCHED_IN); fix_text = gtk_text_view_new (); GLADE_HOOKUP_OBJECT (pr_update_dlg, fix_text, FIX_DESCR_EDIT); gtk_container_add (GTK_CONTAINER (fix_scroll), fix_text); gtk_text_view_set_editable (GTK_TEXT_VIEW (fix_text), TRUE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (fix_text), GTK_WRAP_WORD); buff = gtk_text_view_get_buffer (GTK_TEXT_VIEW (fix_text)); g_signal_connect (buff, "changed", G_CALLBACK (on_text_buffer_changed), pr_update_dlg); g_signal_connect (buff, "changed", G_CALLBACK (check_fix_tab_text), pr_update_dlg); change_log_scroll = gtk_scrolled_window_new (NULL, NULL); GLADE_HOOKUP_OBJECT (pr_update_dlg, change_log_scroll, "change_log_scroll"); gtk_container_add (GTK_CONTAINER (notebook), change_log_scroll); gtk_widget_set_size_request (change_log_scroll, -1, 20); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (change_log_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (change_log_scroll), GTK_SHADOW_ETCHED_IN); change_log_text = gtk_text_view_new (); GLADE_HOOKUP_OBJECT (pr_update_dlg, change_log_text, CHANGE_LOG_TEXT); gtk_container_add (GTK_CONTAINER (change_log_scroll), change_log_text); gtk_text_view_set_editable (GTK_TEXT_VIEW (change_log_text), TRUE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (change_log_text), GTK_WRAP_WORD); buff = gtk_text_view_get_buffer (GTK_TEXT_VIEW (change_log_text)); g_signal_connect (buff, "changed", G_CALLBACK (on_text_buffer_changed), pr_update_dlg); g_signal_connect (buff, "changed", G_CALLBACK (check_chglog_tab_text), pr_update_dlg); audit_trail_scroll = gtk_scrolled_window_new (NULL, NULL); GLADE_HOOKUP_OBJECT (pr_update_dlg, audit_trail_scroll, "audit_trail_scroll"); gtk_container_add (GTK_CONTAINER (notebook), audit_trail_scroll); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (audit_trail_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (audit_trail_scroll), GTK_SHADOW_ETCHED_IN); audit_trail_text = gtk_text_view_new (); GLADE_HOOKUP_OBJECT (pr_update_dlg, audit_trail_text, AUDIT_TRAIL_EDIT); gtk_container_add (GTK_CONTAINER (audit_trail_scroll), audit_trail_text); gtk_text_view_set_editable (GTK_TEXT_VIEW (audit_trail_text), FALSE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (audit_trail_text), GTK_WRAP_WORD); label = gtk_label_new (_("Description")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "tab0lbl"); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0), label); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); label = gtk_label_new (_("Fix Description")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, FIX_TAB_LBL); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1), label); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); label = gtk_label_new (_("ChangeLog Text")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, CHGLOG_TAB_LBL); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2), label); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); label = gtk_label_new (_("Audit Trail")); GLADE_HOOKUP_OBJECT (pr_update_dlg, label, "tab3lbl"); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 3), label); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); gtk_widget_show_all (pr_update_dlg); return pr_update_dlg; }