/*------------------------------------------------------------------------- * Copyright (c) 1999-2004 Kenneth W. Sodemann (stuffle@mac.com) *------------------------------------------------------------------------- * person_dlg * * Synopsis: * Handle the user list dialog and the user editor. * * $Id: person_dlg.c,v 1.55 2004/11/25 23:44:07 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 "db_utils.h" #include "defs.h" #include "error_chks.h" #include "gstr_utils.h" #include "gtkutils.h" #include "prepsmain.h" #include "util.h" /* * Define the names of the significant widgets */ #define PERSON_DIALOG "person_dlg" #define PERSON_LIST_VIEW "person_list_view" #define ADD_BUTTON "add_button" #define MOD_BUTTON "modify_button" #define DEL_BUTTON "delete_button" #define DISMISS_BUTTON "dismiss_button" #define OK_BUTTON "ok_button" #define CANCEL_BUTTON "cancel_button" #define SHOW_INACTIVE_CB "show_inactive_cb" #define PERSON_EDIT_DIALOG "person_edit_dlg" #define LAST_NAME_ENTRY "last_name_entry" #define FIRST_NAME_ENTRY "first_name_entry" #define MIDDLE_NAME_ENTRY "middle_name_entry" #define EMAIL_ENTRY "email_address_entry" #define LOGIN_ID_ENTRY "login_id_entry" #define USER_RB "user_access_rb" #define ADMIN_RB "admin_access_rb" #define ACTIVE_CB "active_cb" #define COLUMN_NUM "column_num" #define LOGIN_ID_COL 2 #define USER_ACCESS 0 #define ADMIN_ACCESS 1 #define NO_PG_USER_MSG _("User '%s' is not set up in PostgreSQL. Be sure to create this user in PostgreSQL.") /* * This is the order in the main SELECT. If the order changes * in 'read_person_data', these must change to match it. * * These defines also tie in to the order of the SELECT that follows * them (which is used for the modify dialog). */ #define LOGIN_ID_POS 0 #define LAST_NAME_POS 1 #define FIRST_NAME_POS 2 #define ACTIVE_POS 3 #define ACCESS_FLAG_POS 4 #define MIDDLE_NAME_POS 5 #define E_MAIL_POS 6 #define PERSON_QUERY "SELECT login_id, last_name, first_name, active, \ access_flag, middle_name, e_mail \ FROM person \ WHERE person.login_id = '%s' " enum { PERSON_LAST_NAME = 0, PERSON_MID_NAME, PERSON_FIRST_NAME, PERSON_LOGIN_ID, PERSON_E_MAIL, PERSON_IS_ADMIN, PERSON_IS_ACTIVE, PERSON_IS_EDITABLE, NUM_PERSON_COLS }; static const gchar *my_child_list = "CHILD_LIST"; /* * The single allowed person list dialog box. */ static GtkWidget *person_dlg = NULL; /* * Local prototypes */ static gboolean draw_person_list (GtkWindow *parent, PGconn *conn); static gboolean check_pg_user (PGconn *conn, const gchar *login_id) { GString *sql; PGresult *res; gint cnt = 0; sql = g_string_new ("select count (*) from pg_user where usename = "); g_string_append_printf (sql, "'%s' ", login_id); res = PQexec (conn, sql->str); if (chk_sql_error (res, _("Check if user exists in PostgreSQL"))) { g_assert (PQntuples (res) == 1); cnt = atoi (PQgetvalue (res, 0, 0)); } PQclear (res); g_string_free (sql, TRUE); return (cnt > 0); } static GString * build_insert_string (GtkDialog *dlg) { GtkWidget *widget; GtkRadioButton *user_rb; GtkRadioButton *admin_rb; GString *str; GString *tmp; gint access_cd = USER_ACCESS; tmp = g_string_new (""); str = g_string_new ("INSERT INTO person (login_id, last_name, "); str = g_string_append (str, "first_name, middle_name, e_mail, "); str = g_string_append (str, "active, access_flag) VALUES ("); widget = lookup_widget (GTK_WIDGET (dlg), LOGIN_ID_ENTRY); g_assert (widget != NULL); tmp = g_string_assign (tmp, gtk_entry_get_text (GTK_ENTRY (widget))); g_string_prepare_db_instr (tmp); str = g_string_append (str, tmp->str); str = g_string_append (str, ", "); widget = lookup_widget (GTK_WIDGET (dlg), LAST_NAME_ENTRY); g_assert (widget != NULL); tmp = g_string_assign (tmp, gtk_entry_get_text (GTK_ENTRY (widget))); g_string_prepare_db_instr (tmp); str = g_string_append (str, tmp->str); str = g_string_append (str, ", "); widget = lookup_widget (GTK_WIDGET (dlg), FIRST_NAME_ENTRY); g_assert (widget != NULL); tmp = g_string_assign (tmp, gtk_entry_get_text (GTK_ENTRY (widget))); g_string_prepare_db_instr (tmp); str = g_string_append (str, tmp->str); str = g_string_append (str, ", "); widget = lookup_widget (GTK_WIDGET (dlg), MIDDLE_NAME_ENTRY); g_assert (widget != NULL); tmp = g_string_assign (tmp, gtk_entry_get_text (GTK_ENTRY (widget))); g_string_prepare_db_instr (tmp); str = g_string_append (str, tmp->str); str = g_string_append (str, ", "); widget = lookup_widget (GTK_WIDGET (dlg), EMAIL_ENTRY); g_assert (widget != NULL); tmp = g_string_assign (tmp, gtk_entry_get_text (GTK_ENTRY (widget))); g_string_prepare_db_instr (tmp); str = g_string_append (str, tmp->str); str = g_string_append (str, ", "); widget = lookup_widget (GTK_WIDGET (dlg), ACTIVE_CB); g_assert (widget != NULL); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { str = g_string_append (str, "TRUE, "); } else { str = g_string_append (str, "FALSE, "); } user_rb = GTK_RADIO_BUTTON (lookup_widget (GTK_WIDGET (dlg), USER_RB)); admin_rb = GTK_RADIO_BUTTON (lookup_widget (GTK_WIDGET (dlg), ADMIN_RB)); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (user_rb))) { access_cd = USER_ACCESS; } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (admin_rb))) { access_cd = ADMIN_ACCESS; } else { g_assert_not_reached (); } g_string_printf (tmp, "%d", access_cd); str = g_string_append (str, tmp->str); str = g_string_append (str, ")"); g_string_free (tmp, TRUE); return str; } static gboolean login_id_already_used (PGconn *conn, GtkDialog *dlg, const gchar *id) { PGresult *res; GString *sql; GString *idstr; gboolean exists = FALSE; idstr = g_string_new (id); g_string_prepare_db_instr (idstr); sql = g_string_new ("SELECT first_name, last_name "); sql = g_string_append (sql, "FROM person "); g_string_append_printf (sql, "WHERE login_id = %s", idstr->str); res = PQexec (conn, sql->str); if (chk_sql_error (res, _("Determining if login ID exists"))) { if (PQntuples (res) > 0) { GtkWidget *err_dlg; GString *err = g_string_new (""); exists = TRUE; g_string_printf (err, _("PostgreSQL ID %s is already used for user: %s %s."), id, PQgetvalue (res, 0, 0), PQgetvalue (res, 0, 1)); err = g_string_append (err, _("You must use unique PostgreSQL IDs for each user.")); err_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, err->str); gtk_dialog_run (GTK_DIALOG (err_dlg)); gtk_widget_destroy (err_dlg); g_string_free (err, TRUE); } } PQclear (res); g_string_free (idstr, TRUE); g_string_free (sql, TRUE); return exists; } static void on_ok_button_clicked (GtkDialog *dlg) { PGresult *res; gboolean in_error = FALSE; PGconn *conn; GtkWidget *parent; GtkWidget *widget; GString *sqlstr; conn = g_object_get_data (G_OBJECT (dlg), MY_DB_CONN); g_assert (conn != NULL); parent = g_object_get_data (G_OBJECT (dlg), MY_PARENT); g_assert (parent != NULL); /* * Check that there is something in the widgets that are required. */ widget = lookup_widget (GTK_WIDGET (dlg), FIRST_NAME_ENTRY); g_assert (widget != NULL); if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) == 0) { GtkWidget *err_dlg; GString *msg_str = g_string_new (_("First Name is required.")); err_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (err_dlg)); gtk_widget_destroy (err_dlg); g_string_free (msg_str, TRUE); return; } widget = lookup_widget (GTK_WIDGET (dlg), LAST_NAME_ENTRY); g_assert (widget != NULL); if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) == 0) { GtkWidget *err_dlg; GString *msg_str = g_string_new (_("Last Name is required.")); err_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (err_dlg)); gtk_widget_destroy (err_dlg); g_string_free (msg_str, TRUE); return; } widget = lookup_widget (GTK_WIDGET (dlg), LOGIN_ID_ENTRY); g_assert (widget != NULL); if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) == 0) { GtkWidget *err_dlg; GString *msg_str = g_string_new (_("Login ID is required.")); err_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (err_dlg)); gtk_widget_destroy (err_dlg); g_string_free (msg_str, TRUE); return; } if (login_id_already_used (conn, dlg, gtk_entry_get_text (GTK_ENTRY (widget)))) { /* * The login_id_already_used() function will display the error * dialog, since it can provide all of the information that makes * life nice for the users. Thus, we only need to return here... */ return; } if (!check_pg_user (conn, gtk_entry_get_text (GTK_ENTRY (widget)))) { GtkWidget *err_dlg; GString *msg_str = g_string_new (""); g_string_printf (msg_str, NO_PG_USER_MSG, gtk_entry_get_text (GTK_ENTRY (widget))); err_dlg = gtk_message_dialog_new (GTK_WINDOW (dlg), 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msg_str->str); gtk_dialog_run (GTK_DIALOG (err_dlg)); gtk_widget_destroy (err_dlg); g_string_free (msg_str, TRUE); } START_TRANSACTION (conn); sqlstr = build_insert_string (dlg); res = PQexec (conn, sqlstr->str); in_error = !chk_sql_error (res, _("inserting user data")); g_string_free (sqlstr, TRUE); if (!in_error) { draw_person_list (GTK_WINDOW (parent), conn); gtk_widget_destroy (GTK_WIDGET (dlg)); } finalize_transaction (conn, res); PQclear (res); } static void on_cancel_button_clicked (GtkDialog *dlg) { gtk_widget_destroy (GTK_WIDGET (dlg)); } static void on_person_edit_dlg_clicked (GtkDialog *dlg, gint btn_cd, gpointer user_data) { switch (btn_cd) { case GTK_RESPONSE_OK: on_ok_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(); } } static GtkWidget* create_person_edit_dlg (PGconn *conn, GtkWidget *parent) { GtkWidget *person_edit_dlg; GtkWidget *dialog_vbox9; GtkWidget *table3; GtkWidget *label5; GtkWidget *last_name_entry; GtkWidget *login_id_entry; GtkWidget *email_address_entry; GtkWidget *frame3; GtkWidget *vbox21; GSList *vbox21_group = NULL; GtkWidget *user_access_rb; GtkWidget *admin_access_rb; GtkWidget *label3; GtkWidget *label1; GtkWidget *label2; GtkWidget *first_name_entry; GtkWidget *middle_name_entry; GtkWidget *label4; GtkWidget *active_cb; GtkTooltips *tooltips; GConfClient *client; tooltips = g_object_get_data (G_OBJECT (parent), TOOLTIPS); g_assert (tooltips != NULL); client = g_object_get_data (G_OBJECT (parent), MY_GCONF_CLIENT); g_assert (client != NULL); person_edit_dlg = gtk_dialog_new_with_buttons (_("Add User"), GTK_WINDOW (parent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); GLADE_HOOKUP_OBJECT_NO_REF (person_edit_dlg, person_edit_dlg, PERSON_EDIT_DIALOG); gtk_container_set_border_width (GTK_CONTAINER (person_edit_dlg), 5); g_signal_connect (person_edit_dlg, "response", G_CALLBACK (on_person_edit_dlg_clicked), NULL); gtk_window_set_resizable (GTK_WINDOW (person_edit_dlg), FALSE); gtk_dialog_set_default_response (GTK_DIALOG (person_edit_dlg), GTK_RESPONSE_OK); g_object_set_data (G_OBJECT (person_edit_dlg), TOP_DOG, person_edit_dlg); g_object_set_data (G_OBJECT (person_edit_dlg), MY_PARENT, parent); g_object_set_data (G_OBJECT (person_edit_dlg), MY_DB_CONN, conn); g_object_set_data (G_OBJECT (person_edit_dlg), MY_GCONF_CLIENT, client); dialog_vbox9 = GTK_DIALOG (person_edit_dlg)->vbox; GLADE_HOOKUP_OBJECT (person_edit_dlg, dialog_vbox9, "dialog_vbox9"); gtk_box_set_spacing (GTK_BOX (dialog_vbox9), 5); gtk_widget_show (dialog_vbox9); table3 = gtk_table_new (4, 4, FALSE); GLADE_HOOKUP_OBJECT (person_edit_dlg, table3, "table3"); gtk_widget_show (table3); gtk_box_pack_start (GTK_BOX (dialog_vbox9), table3, TRUE, TRUE, 0); gtk_table_set_row_spacings (GTK_TABLE (table3), 3); gtk_table_set_col_spacings (GTK_TABLE (table3), 3); label5 = gtk_label_new (_("E-Mail Address:")); GLADE_HOOKUP_OBJECT (person_edit_dlg, label5, "label5"); gtk_widget_show (label5); gtk_table_attach (GTK_TABLE (table3), label5, 2, 3, 2, 3, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment (GTK_MISC (label5), 0, 0.5); last_name_entry = gtk_entry_new (); GLADE_HOOKUP_OBJECT (person_edit_dlg, last_name_entry, LAST_NAME_ENTRY); gtk_widget_show (last_name_entry); gtk_table_attach (GTK_TABLE (table3), last_name_entry, 1, 2, 0, 1, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_tooltips_set_tip (tooltips, last_name_entry, _("Last name is required."), NULL); login_id_entry = gtk_entry_new (); GLADE_HOOKUP_OBJECT (person_edit_dlg, login_id_entry, LOGIN_ID_ENTRY); gtk_widget_show (login_id_entry); gtk_table_attach (GTK_TABLE (table3), login_id_entry, 1, 2, 2, 3, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_tooltips_set_tip (tooltips, login_id_entry, _("This user's PostgreSQL login ID (usually matches the system login ID)."), NULL); email_address_entry = gtk_entry_new (); GLADE_HOOKUP_OBJECT (person_edit_dlg, email_address_entry, EMAIL_ENTRY); gtk_widget_show (email_address_entry); gtk_table_attach (GTK_TABLE (table3), email_address_entry, 3, 4, 2, 3, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_tooltips_set_tip (tooltips, email_address_entry, _("Optional e-mail address must be fully qualified if not local."), NULL); frame3 = gtk_frame_new (_("Access")); GLADE_HOOKUP_OBJECT (person_edit_dlg, frame3, "frame3"); gtk_widget_show (frame3); gtk_table_attach (GTK_TABLE (table3), frame3, 0, 2, 3, 4, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); vbox21 = gtk_vbox_new (FALSE, 0); GLADE_HOOKUP_OBJECT (person_edit_dlg, vbox21, "vbox21"); gtk_widget_show (vbox21); gtk_container_add (GTK_CONTAINER (frame3), vbox21); user_access_rb = gtk_radio_button_new_with_label (vbox21_group, _("User")); GLADE_HOOKUP_OBJECT (person_edit_dlg, user_access_rb, USER_RB); vbox21_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (user_access_rb)); gtk_widget_show (user_access_rb); gtk_box_pack_start (GTK_BOX (vbox21), user_access_rb, TRUE, TRUE, 0); admin_access_rb = gtk_radio_button_new_with_label (vbox21_group, _("Administrator")); GLADE_HOOKUP_OBJECT (person_edit_dlg, admin_access_rb, ADMIN_RB); vbox21_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (admin_access_rb)); gtk_widget_show (admin_access_rb); gtk_box_pack_start (GTK_BOX (vbox21), admin_access_rb, TRUE, TRUE, 0); label3 = gtk_label_new (_("Last Name:")); GLADE_HOOKUP_OBJECT (person_edit_dlg, label3, "label3"); gtk_widget_show (label3); gtk_table_attach (GTK_TABLE (table3), label3, 0, 1, 0, 1, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5); label1 = gtk_label_new (_("PostgreSQL ID:")); GLADE_HOOKUP_OBJECT (person_edit_dlg, label1, "label1"); gtk_widget_show (label1); gtk_table_attach (GTK_TABLE (table3), label1, 0, 1, 2, 3, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5); label2 = gtk_label_new (_("First Name:")); GLADE_HOOKUP_OBJECT (person_edit_dlg, label2, "label2"); gtk_widget_show (label2); gtk_table_attach (GTK_TABLE (table3), label2, 2, 3, 0, 1, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5); first_name_entry = gtk_entry_new (); GLADE_HOOKUP_OBJECT (person_edit_dlg, first_name_entry, FIRST_NAME_ENTRY); gtk_widget_show (first_name_entry); gtk_table_attach (GTK_TABLE (table3), first_name_entry, 3, 4, 0, 1, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_tooltips_set_tip (tooltips, first_name_entry, _("First name is required."), NULL); middle_name_entry = gtk_entry_new (); GLADE_HOOKUP_OBJECT (person_edit_dlg, middle_name_entry, MIDDLE_NAME_ENTRY); gtk_widget_show (middle_name_entry); gtk_table_attach (GTK_TABLE (table3), middle_name_entry, 1, 2, 1, 2, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_tooltips_set_tip (tooltips, middle_name_entry, _("Middle name (or initial) is optional."), NULL); label4 = gtk_label_new (_("Middle Name:")); GLADE_HOOKUP_OBJECT (person_edit_dlg, label4, "label4"); gtk_widget_show (label4); gtk_table_attach (GTK_TABLE (table3), label4, 0, 1, 1, 2, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5); active_cb = gtk_check_button_new_with_label (_("Active")); GLADE_HOOKUP_OBJECT (person_edit_dlg, active_cb, "active_cb"); gtk_widget_show (active_cb); gtk_table_attach (GTK_TABLE (table3), active_cb, 2, 3, 1, 2, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_cb), TRUE); g_object_set_data (G_OBJECT (person_edit_dlg), TOOLTIPS, tooltips); return person_edit_dlg; } /*-------------------------------------------------------------------------- * Local support functions for the person_dlg dialog. * * read_person_data : read the person data from the database * draw_person_list : draw the person list *-------------------------------------------------------------------------- */ static PGresult * read_person_data (PGconn *conn, gboolean show_inactive) { GString *buffer; PGresult *result; /* * The order in the following SELECT is tied to #define's at * the start of the file. Change this, and be sure to * change those to match. */ buffer = g_string_new ("SELECT login_id, last_name, first_name, "); buffer = g_string_append (buffer, "active, access_flag, middle_name, "); buffer = g_string_append (buffer, "e_mail "); buffer = g_string_append (buffer, "FROM person "); if (!show_inactive) { buffer = g_string_append (buffer, "WHERE active = TRUE "); } buffer = g_string_append (buffer, "ORDER BY 2, 3, 1 "); result = PQexec (conn, buffer->str); g_string_free (buffer, TRUE); return result; } static PGresult * delete_person (PGconn *conn, const gchar *login_id) { GString *buffer; PGresult *res; buffer = g_string_new (""); g_string_printf (buffer, "DELETE FROM person WHERE login_id = '%s'", login_id); res = PQexec (conn, buffer->str); g_string_free (buffer, TRUE); return res; } static gboolean person_is_active (PGresult *res, int n) { if (n >= PQntuples (res)) { return FALSE; } if ((PQgetvalue (res, n, ACTIVE_POS))[0] == 't') { return TRUE; } return FALSE; } static gboolean person_is_admin (PGresult *res, int n) { if (n >= PQntuples (res)) { return FALSE; } if (atoi (PQgetvalue (res, n, ACCESS_FLAG_POS)) == 1) { return TRUE; } return FALSE; } static gboolean draw_person_list (GtkWindow *parent, PGconn *conn) { gint ntuples; gint i; PGresult *res; GtkTreeView *tree; GtkListStore *store; GtkTreeIter iter; GtkCheckButton *cb_widget; gboolean show_inactive; gboolean rtn_val = FALSE; gboolean editable; tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET(parent), PERSON_LIST_VIEW)); g_assert (tree != NULL); cb_widget = GTK_CHECK_BUTTON (lookup_widget (GTK_WIDGET (parent), SHOW_INACTIVE_CB)); g_assert (cb_widget != NULL); show_inactive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb_widget)); store = GTK_LIST_STORE (gtk_tree_view_get_model (tree)); gtk_list_store_clear (store); editable = (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (parent), ADMIN_USER)) == 1); res = read_person_data (conn, show_inactive); if (chk_sql_error (res, _("reading person data"))) { ntuples = PQntuples (res); for (i = 0; i < ntuples; i++) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, PERSON_LAST_NAME, PQgetvalue (res, i, LAST_NAME_POS), PERSON_MID_NAME, PQgetvalue (res, i, MIDDLE_NAME_POS), PERSON_FIRST_NAME, PQgetvalue (res, i, FIRST_NAME_POS), PERSON_LOGIN_ID, PQgetvalue (res, i, LOGIN_ID_POS), PERSON_E_MAIL, PQgetvalue (res, i, E_MAIL_POS), PERSON_IS_ADMIN, person_is_admin (res, i), PERSON_IS_ACTIVE, person_is_active (res, i), PERSON_IS_EDITABLE, editable, -1); } rtn_val = TRUE; } PQclear (res); return rtn_val; } /*-------------------------------------------------------------------------- * Signal handlers for the person list dialog. *-------------------------------------------------------------------------- */ static void on_person_dlg_show (GtkWidget *widget, gpointer user_data) { GtkToggleButton *cb; GString *config_str; gboolean flag; GConfClient *client; GError *error = NULL; config_str = g_string_new (""); client = g_object_get_data (G_OBJECT (widget), MY_GCONF_CLIENT); g_assert (client != NULL); cb = GTK_TOGGLE_BUTTON (lookup_widget (widget, SHOW_INACTIVE_CB)); g_assert (cb != NULL); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, WINSTATES, USER_DLG_SEC, SHOW_INACT); flag = gconf_client_get_bool (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; flag = FALSE; } gtk_toggle_button_set_active (cb, flag); g_string_free (config_str, TRUE); if (!draw_person_list (GTK_WINDOW (widget), user_data)) { gtk_widget_destroy (widget); } } static void on_person_dlg_destroy (GObject *object, gpointer user_data) { GList *child_list; GList *list_iter; GtkToggleButton *cb; GString *config_str; GConfClient *client; config_str = g_string_new (""); client = g_object_get_data (object, MY_GCONF_CLIENT); g_assert (client != NULL); cb = GTK_TOGGLE_BUTTON (lookup_widget (GTK_WIDGET (object), SHOW_INACTIVE_CB)); g_assert (cb != NULL); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, WINSTATES, USER_DLG_SEC, SHOW_INACT); gconf_client_set_bool (client, config_str->str, gtk_toggle_button_get_active (cb), NULL); g_string_free (config_str, TRUE); child_list = g_object_get_data (G_OBJECT (object), my_child_list); list_iter = g_list_first (child_list); while (list_iter) { g_signal_handlers_block_by_func (GTK_OBJECT (list_iter->data), G_CALLBACK (child_dead), (gpointer)my_child_list); gtk_widget_destroy (GTK_WIDGET (list_iter->data)); list_iter = list_iter->next; } g_list_free (child_list); } static void person_edited (GtkCellRendererText *cell, const gchar *path_str, const gchar *new_text, gpointer data) { GtkTreeView *tree; GtkTreePath *path; GtkListStore *store; GtkTreeIter iter; PGconn *conn; PGresult *res; GString *sql; GString *str = g_string_new (new_text); gchar *id; gint column; tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET (data), PERSON_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); column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), COLUMN_NUM)); g_assert (column == PERSON_LAST_NAME || column == PERSON_MID_NAME || column == PERSON_FIRST_NAME || column == PERSON_E_MAIL); /* * Some items cannot be NULL. If this is one of those items, and * the new value is NULL, just ignore the change. * * The string that is prepared here will be used when building * the update SQL. */ g_string_prepare_db_instr (str); if (strcmp (str->str, "NULL") == 0 && (column == PERSON_FIRST_NAME || column == PERSON_LAST_NAME)) { g_string_free (str, TRUE); return; } path = gtk_tree_path_new_from_string (path_str); gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, PERSON_LOGIN_ID, &id, -1); /* * Build the update SQL. */ sql = g_string_new ("update person set "); switch (column) { case PERSON_LAST_NAME: sql = g_string_append (sql, "last_name = "); sql = g_string_append (sql, str->str); break; case PERSON_MID_NAME: sql = g_string_append (sql, "middle_name = "); sql = g_string_append (sql, str->str); break; case PERSON_FIRST_NAME: sql = g_string_append (sql, "first_name = "); sql = g_string_append (sql, str->str); break; case PERSON_E_MAIL: sql = g_string_append (sql, "e_mail = "); sql = g_string_append (sql, str->str); break; default: g_assert_not_reached (); break; } sql = g_string_append (sql, " where login_id = '"); sql = g_string_append (sql, id); sql = g_string_append (sql, "' "); START_TRANSACTION (conn); res = PQexec (conn, sql->str); if (chk_sql_error (res, _("Update User Information"))) { gtk_list_store_set (store, &iter, column, new_text, -1); } gtk_tree_path_free (path); g_string_free (sql, TRUE); g_string_free (str, TRUE); finalize_transaction (conn, res); PQclear (res); } static void person_toggled(GtkCellRendererToggle *cell, gchar *path_str, gpointer data) { GtkTreeView *tree; GtkTreePath *path = gtk_tree_path_new_from_string (path_str); GtkListStore *store; GtkTreeIter iter; PGconn *conn; PGresult *res; GString *sql; gint column; gchar *id; gboolean active; gboolean admin; gboolean editable; tree = GTK_TREE_VIEW (lookup_widget (GTK_WIDGET (data), PERSON_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); column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), COLUMN_NUM)); g_assert (column == PERSON_IS_ACTIVE || column == PERSON_IS_ADMIN); gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, PERSON_IS_ACTIVE, &active, PERSON_IS_ADMIN, &admin, PERSON_LOGIN_ID, &id, PERSON_IS_EDITABLE, &editable, -1); /* * If the current user is attempting to revoke their own admin access, * warn them. If they don't really intend on revoking their own admin * access, just set the editable flag to FALSE (this will force the * change to not be made. */ if (column == PERSON_IS_ADMIN && admin && strcmp (PQuser (conn), id) == 0) { GtkWidget *msg_dlg; msg_dlg = gtk_message_dialog_new (GTK_WINDOW (data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Removing admin access takes place immediatly. If you remove admin access for your own user, you will not be able to perform any more administrative tasks. Are you sure you want to do this?")); gtk_dialog_set_default_response (GTK_DIALOG (msg_dlg), GTK_RESPONSE_NO); editable = (gtk_dialog_run (GTK_DIALOG (msg_dlg)) == GTK_RESPONSE_YES); gtk_widget_destroy (msg_dlg); } if (editable) { sql = g_string_new ("update person set "); switch (column) { case PERSON_IS_ACTIVE: sql = g_string_append (sql, "active = "); if (active) { active = FALSE; sql = g_string_append (sql, "FALSE "); } else { active = TRUE; sql = g_string_append (sql, "TRUE "); } break; case PERSON_IS_ADMIN: sql = g_string_append (sql, "access_flag = "); if (admin) { admin = FALSE; sql = g_string_append (sql, "0 "); } else { admin = TRUE; sql = g_string_append (sql, "1 "); } break; default: g_assert_not_reached (); break; } sql = g_string_append (sql, "where login_id = '"); sql = g_string_append (sql, id); sql = g_string_append (sql, "' "); START_TRANSACTION (conn); res = PQexec (conn, sql->str); if (chk_sql_error (res, _("Update User Active/Access"))) { gtk_list_store_set (store, &iter, PERSON_IS_ACTIVE, active, PERSON_IS_ADMIN, admin, -1); } finalize_transaction (conn, res); PQclear (res); g_string_free (sql, TRUE); } g_free (id); gtk_tree_path_free (path); } static void on_person_dlg_clicked (GtkDialog *dlg, gint btn, gpointer user_data) { GConfClient *client; client = g_object_get_data (G_OBJECT (dlg), MY_GCONF_CLIENT); g_assert (client != NULL); save_dlg_size (client, GTK_WIDGET (dlg), USER_DLG_SEC); gtk_widget_destroy (GTK_WIDGET (dlg)); } static void on_add_user (GtkWidget *widget, gpointer user_data) { GtkWidget *dlg; PGconn *conn; gboolean admin_user; 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); dlg = create_person_edit_dlg (conn, GTK_WIDGET (user_data)); gtk_widget_show (dlg); } static void on_delete_user (GtkButton *button, gpointer user_data) { GtkTreeView *tree; GtkTreeModel *model; GtkTreeSelection *sel; GtkTreeIter iter; PGresult *res; gchar *id; PGconn *conn; GtkWidget *msg_dlg; 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), PERSON_LIST_VIEW)); g_assert (tree != NULL); model = gtk_tree_view_get_model (tree); sel = gtk_tree_view_get_selection (tree); 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_QUESTION, GTK_BUTTONS_YES_NO, _("Deleting a person is not reversable.\n""Are you sure you want to continue?")); gtk_dialog_set_default_response (GTK_DIALOG (msg_dlg), GTK_RESPONSE_NO); if (gtk_dialog_run (GTK_DIALOG (msg_dlg)) == GTK_RESPONSE_YES) { gtk_tree_model_get (model, &iter, PERSON_LOGIN_ID, &id, -1); START_TRANSACTION (conn); res = delete_person (conn, id); if (chk_sql_error (res, _("Person Delete Failed"))) { gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } /*draw_person_list (GTK_WINDOW (user_data), conn);*/ finalize_transaction (conn, res); g_free (id); PQclear (res); } gtk_widget_destroy (msg_dlg); } else { msg_dlg = gtk_message_dialog_new (GTK_WINDOW (user_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("To delete a user, you must select a user to delete.")); gtk_dialog_run (GTK_DIALOG (msg_dlg)); gtk_widget_destroy (msg_dlg); } } static void on_show_inactive_cb_toggled (GtkToggleButton *togglebutton, gpointer user_data) { PGconn *conn; conn = g_object_get_data (G_OBJECT (user_data), MY_DB_CONN); g_assert (conn != NULL); draw_person_list (GTK_WINDOW (user_data), conn); } static GtkWidget* create_person_dlg (GtkWidget *parent, PGconn *conn, gboolean user_is_admin) { GtkWidget *person_dlg; GtkWidget *dialog_vbox11; GtkWidget *vbox23; GtkWidget *scrolledwindow4; GtkWidget *person_list_view; GtkListStore *person_list_store; GtkCellRenderer *rend; GtkTreeViewColumn *col; GtkWidget *hbox27; GtkWidget *add_button; GtkWidget *delete_button; GtkWidget *show_inactive_cb; GtkWidget *warn_hbox; GtkWidget *warn_icon; GtkWidget *warn_lbl; GtkTooltips *tooltips; GConfClient *client; tooltips = g_object_get_data (G_OBJECT (parent), TOOLTIPS); g_assert (tooltips != NULL); client = g_object_get_data (G_OBJECT (parent), MY_GCONF_CLIENT); g_assert (client != NULL); person_dlg = gtk_dialog_new_with_buttons (_("Users"), GTK_WINDOW (parent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); GLADE_HOOKUP_OBJECT_NO_REF (person_dlg, person_dlg, PERSON_DIALOG); gtk_container_set_border_width (GTK_CONTAINER (person_dlg), 5); g_signal_connect (person_dlg, "show", G_CALLBACK (on_person_dlg_show), conn); gtk_window_set_resizable (GTK_WINDOW (person_dlg), TRUE); g_signal_connect (person_dlg, "destroy", G_CALLBACK (on_person_dlg_destroy), NULL); g_signal_connect (person_dlg, "response", G_CALLBACK (on_person_dlg_clicked), NULL); set_dlg_size (client, person_dlg, USER_DLG_SEC, 590, 265); g_object_set_data (G_OBJECT (person_dlg), TOP_DOG, person_dlg); g_object_set_data (G_OBJECT (person_dlg), MY_DB_CONN, conn); g_object_set_data (G_OBJECT (person_dlg), MY_GCONF_CLIENT, client); g_object_set_data (G_OBJECT (person_dlg), ADMIN_USER, GINT_TO_POINTER (user_is_admin ? 1 : 0)); dialog_vbox11 = GTK_DIALOG (person_dlg)->vbox; GLADE_HOOKUP_OBJECT (person_dlg, dialog_vbox11, "dialog_vbox11"); gtk_box_set_spacing (GTK_BOX (dialog_vbox11), STD_BOX_SPACING); gtk_widget_show (dialog_vbox11); vbox23 = gtk_vbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (person_dlg, vbox23, "vbox23"); gtk_widget_show (vbox23); gtk_box_pack_start (GTK_BOX (dialog_vbox11), vbox23, TRUE, TRUE, 0); scrolledwindow4 = gtk_scrolled_window_new (NULL, NULL); GLADE_HOOKUP_OBJECT (person_dlg, scrolledwindow4, "scrolledwindow4"); gtk_widget_show (scrolledwindow4); gtk_box_pack_start (GTK_BOX (vbox23), scrolledwindow4, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_SHADOW_ETCHED_IN); person_list_store = gtk_list_store_new (NUM_PERSON_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); person_list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (person_list_store)); GLADE_HOOKUP_OBJECT (person_dlg, person_list_view, PERSON_LIST_VIEW); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (person_list_view), TRUE); gtk_container_add (GTK_CONTAINER (scrolledwindow4), person_list_view); gtk_widget_show (person_list_view); rend = gtk_cell_renderer_text_new (); g_signal_connect (rend, "edited", G_CALLBACK (person_edited), person_dlg); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_LAST_NAME)); col = gtk_tree_view_column_new_with_attributes (_("Last Name"), rend, "text", PERSON_LAST_NAME, "editable", PERSON_IS_EDITABLE, NULL); gtk_tree_view_column_set_sort_column_id (col, PERSON_LAST_NAME); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); rend = gtk_cell_renderer_text_new (); g_signal_connect (rend, "edited", G_CALLBACK (person_edited), person_dlg); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_MID_NAME)); col = gtk_tree_view_column_new_with_attributes (_("Middle Name"), rend, "text", PERSON_MID_NAME, "editable", PERSON_IS_EDITABLE, NULL); gtk_tree_view_column_set_sort_column_id (col, PERSON_MID_NAME); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); rend = gtk_cell_renderer_text_new (); g_signal_connect (rend, "edited", G_CALLBACK (person_edited), person_dlg); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_FIRST_NAME)); col = gtk_tree_view_column_new_with_attributes (_("First Name"), rend, "text", PERSON_FIRST_NAME, "editable", PERSON_IS_EDITABLE, NULL); gtk_tree_view_column_set_sort_column_id (col, PERSON_FIRST_NAME); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); rend = gtk_cell_renderer_text_new (); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_LOGIN_ID)); col = gtk_tree_view_column_new_with_attributes (_("Login Id"), rend, "text", PERSON_LOGIN_ID, NULL); gtk_tree_view_column_set_sort_column_id (col, PERSON_LOGIN_ID); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); rend = gtk_cell_renderer_text_new (); g_signal_connect (rend, "edited", G_CALLBACK (person_edited), person_dlg); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_E_MAIL)); col = gtk_tree_view_column_new_with_attributes (_("E-mail Address"), rend, "text", PERSON_E_MAIL, "editable", PERSON_IS_EDITABLE, NULL); gtk_tree_view_column_set_sort_column_id (col, PERSON_E_MAIL); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); rend = gtk_cell_renderer_toggle_new (); g_signal_connect (rend, "toggled", G_CALLBACK (person_toggled), person_dlg); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_IS_ADMIN)); col = gtk_tree_view_column_new_with_attributes (_("Administrator"), rend, "active", PERSON_IS_ADMIN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); rend = gtk_cell_renderer_toggle_new (); g_signal_connect (rend, "toggled", G_CALLBACK (person_toggled), person_dlg); g_object_set_data (G_OBJECT (rend), COLUMN_NUM, GINT_TO_POINTER (PERSON_IS_ACTIVE)); col = gtk_tree_view_column_new_with_attributes (_("Active"), rend, "active", PERSON_IS_ACTIVE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (person_list_view), col); hbox27 = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (person_dlg, hbox27, "hbox27"); gtk_widget_show (hbox27); gtk_box_pack_start (GTK_BOX (vbox23), hbox27, FALSE, FALSE, 0); add_button = gtk_button_new_from_stock (GTK_STOCK_ADD); GLADE_HOOKUP_OBJECT (person_dlg, add_button, ADD_BUTTON); gtk_widget_show (add_button); gtk_box_pack_start (GTK_BOX (hbox27), add_button, TRUE, TRUE, 0); gtk_tooltips_set_tip (tooltips, add_button, _("Add a person."), NULL); g_signal_connect (add_button, "clicked", G_CALLBACK (on_add_user), person_dlg); gtk_widget_set_sensitive (add_button, user_is_admin); delete_button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); GLADE_HOOKUP_OBJECT (person_dlg, delete_button, DEL_BUTTON); gtk_widget_show (delete_button); gtk_box_pack_start (GTK_BOX (hbox27), delete_button, TRUE, TRUE, 0); gtk_tooltips_set_tip (tooltips, delete_button, _("Delete an existing person. If the person is referenced in problem report or project, the user cannot be deleted, but can be made inactive."), NULL); g_signal_connect (delete_button, "clicked", G_CALLBACK (on_delete_user), person_dlg); gtk_widget_set_sensitive (delete_button, user_is_admin); show_inactive_cb = gtk_check_button_new_with_label (_("Show Inactive Persons")); GLADE_HOOKUP_OBJECT (person_dlg, show_inactive_cb, SHOW_INACTIVE_CB); gtk_widget_show (show_inactive_cb); gtk_box_pack_start (GTK_BOX (hbox27), show_inactive_cb, TRUE, TRUE, 0); g_signal_connect (show_inactive_cb, "toggled", G_CALLBACK (on_show_inactive_cb_toggled), person_dlg); if (!user_is_admin) { warn_hbox = gtk_hbox_new (FALSE, STD_BOX_SPACING); GLADE_HOOKUP_OBJECT (person_dlg, warn_hbox, "warn1_hbox"); gtk_box_pack_start (GTK_BOX (dialog_vbox11), warn_hbox, FALSE, FALSE, 0); gtk_widget_show (warn_hbox); warn_icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR); GLADE_HOOKUP_OBJECT (person_dlg, warn_icon, "warn1_icon"); gtk_box_pack_start (GTK_BOX (warn_hbox), warn_icon, FALSE, FALSE, 0); gtk_widget_show (warn_icon); warn_lbl = gtk_label_new (NULL); GLADE_HOOKUP_OBJECT (person_dlg, warn_lbl, "warn1_lbl"); gtk_label_set_markup (GTK_LABEL (warn_lbl), _("Editing Disabled: only administrators can edit user information.")); gtk_box_pack_start (GTK_BOX (warn_hbox), warn_lbl, FALSE, FALSE, 0); gtk_widget_show (warn_lbl); } g_object_set_data (G_OBJECT (person_dlg), TOOLTIPS, tooltips); return person_dlg; } void destroy_person_dlg (void) { if (person_dlg != NULL) { gtk_widget_destroy (person_dlg); person_dlg = NULL; } } void show_person_dlg (GtkWidget *parent, PGconn *conn, gboolean user_is_admin) { /* * If the dialog box exists, just make sure it is visable, otherwise * create it. */ if (person_dlg != NULL) { gdk_window_show (person_dlg->window); gdk_window_raise (person_dlg->window); } else { person_dlg = create_person_dlg (parent, conn, user_is_admin); /* * When the dialog is destroyed, call gtk_widget_destroyed(), * which will set the "user_data" (&person_dlg in this case) to * NULL. */ g_signal_connect (person_dlg, "destroy", G_CALLBACK (gtk_widget_destroyed), &person_dlg); gtk_widget_show (person_dlg); } } /* * TODO: * * Remove this altogether... */ gboolean person_dlg_dirty (void) { return FALSE; }