1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * merge-properties-dialog.c: document merge properties dialog module
8 * Copyright (C) 2001 Jim Evins <evins@snaught.com>.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "merge-properties-dialog.h"
28 #include <glib/gi18n.h>
29 #include <glade/glade-xml.h>
30 #include <gtk/gtkfilechooserbutton.h>
31 #include <gtk/gtkcombobox.h>
32 #include <gtk/gtkstock.h>
33 #include <gtk/gtktreestore.h>
34 #include <gtk/gtktreeselection.h>
35 #include <gtk/gtkcellrenderertoggle.h>
36 #include <gtk/gtkcellrenderertext.h>
37 #include <gtk/gtklabel.h>
47 /*===========================================*/
48 /* Private data types */
49 /*===========================================*/
51 struct _glMergePropertiesDialogPrivate {
56 GtkWidget *type_combo;
57 GtkWidget *location_vbox;
63 GtkWidget *select_all_button;
64 GtkWidget *unselect_all_button;
76 /* Invisible columns */
78 DATA_COLUMN, /* points to glMergeRecord */
83 /*===========================================*/
85 /*===========================================*/
88 /*===========================================*/
89 /* Local function prototypes */
90 /*===========================================*/
92 static void gl_merge_properties_dialog_finalize (GObject *object);
93 static void gl_merge_properties_dialog_construct (glMergePropertiesDialog *dialog,
97 static void type_changed_cb (GtkWidget *widget,
98 glMergePropertiesDialog *dialog);
100 static void src_changed_cb (GtkWidget *widget,
101 glMergePropertiesDialog *dialog);
103 static void response_cb (glMergePropertiesDialog *dialog,
107 static void load_tree (GtkTreeStore *store,
110 static void record_select_toggled_cb (GtkCellRendererToggle *cell,
112 GtkTreeStore *store);
114 static void select_all_button_clicked_cb (GtkWidget *widget,
115 glMergePropertiesDialog *dialog);
117 static void unselect_all_button_clicked_cb (GtkWidget *widget,
118 glMergePropertiesDialog *dialog);
121 /*****************************************************************************/
122 /* Boilerplate object stuff. */
123 /*****************************************************************************/
124 G_DEFINE_TYPE (glMergePropertiesDialog, gl_merge_properties_dialog, GTK_TYPE_DIALOG);
127 gl_merge_properties_dialog_class_init (glMergePropertiesDialogClass *class)
129 GObjectClass *object_class = G_OBJECT_CLASS (class);
131 gl_debug (DEBUG_MERGE, "");
133 gl_merge_properties_dialog_parent_class = g_type_class_peek_parent (class);
135 object_class->finalize = gl_merge_properties_dialog_finalize;
139 gl_merge_properties_dialog_init (glMergePropertiesDialog *dialog)
141 gl_debug (DEBUG_MERGE, "START");
143 dialog->priv = g_new0 (glMergePropertiesDialogPrivate, 1);
145 gtk_container_set_border_width (GTK_CONTAINER(dialog), GL_HIG_PAD2);
147 gtk_dialog_set_has_separator (GTK_DIALOG(dialog), FALSE);
148 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
149 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
150 GTK_STOCK_OK, GTK_RESPONSE_OK,
153 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
155 g_signal_connect(G_OBJECT (dialog), "response",
156 G_CALLBACK (response_cb), NULL);
159 gl_debug (DEBUG_MERGE, "END");
163 gl_merge_properties_dialog_finalize (GObject *object)
165 glMergePropertiesDialog* dialog = GL_MERGE_PROPERTIES_DIALOG (object);
167 gl_debug (DEBUG_MERGE, "START");
169 g_return_if_fail (object != NULL);
170 g_return_if_fail (GL_IS_MERGE_PROPERTIES_DIALOG (dialog));
171 g_return_if_fail (dialog->priv != NULL);
173 if (dialog->priv->merge != NULL) {
174 g_object_unref (G_OBJECT (dialog->priv->merge));
176 g_free (dialog->priv);
178 G_OBJECT_CLASS (gl_merge_properties_dialog_parent_class)->finalize (object);
179 gl_debug (DEBUG_MERGE, "END");
182 /*****************************************************************************/
183 /* NEW merge properties dialog. */
184 /*****************************************************************************/
186 gl_merge_properties_dialog_new (glLabel *label,
191 gl_debug (DEBUG_MERGE, "START");
193 dialog = GTK_WIDGET (g_object_new (GL_TYPE_MERGE_PROPERTIES_DIALOG, NULL));
195 gl_merge_properties_dialog_construct (GL_MERGE_PROPERTIES_DIALOG (dialog),
198 gl_debug (DEBUG_MERGE, "END");
203 /*--------------------------------------------------------------------------*/
204 /* PRIVATE. Create merge widgets. */
205 /*--------------------------------------------------------------------------*/
207 gl_merge_properties_dialog_construct (glMergePropertiesDialog *dialog,
213 glMergeSrcType src_type;
218 GtkCellRenderer *renderer;
219 GtkTreeViewColumn *column;
220 GtkTreeSelection *selection;
222 gl_debug (DEBUG_MERGE, "START");
224 g_return_if_fail (GL_IS_MERGE_PROPERTIES_DIALOG (dialog));
225 g_return_if_fail (dialog->priv != NULL);
228 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(window));
229 gtk_window_set_destroy_with_parent (GTK_WINDOW(dialog), TRUE);
232 gui = glade_xml_new (GLABELS_GLADE_DIR "merge-properties-dialog.glade",
233 "merge_properties_vbox", NULL);
236 g_critical ("Could not open merge-properties-dialog.glade. gLabels may not be installed correctly!");
240 vbox = glade_xml_get_widget (gui, "merge_properties_vbox");
241 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
243 dialog->priv->type_combo = glade_xml_get_widget (gui, "type_combo");
244 dialog->priv->location_vbox = glade_xml_get_widget (gui, "location_vbox");
245 dialog->priv->treeview = glade_xml_get_widget (gui, "treeview");
247 dialog->priv->select_all_button = glade_xml_get_widget (gui, "select_all_button");
248 dialog->priv->unselect_all_button = glade_xml_get_widget (gui, "unselect_all_button");
250 g_object_unref (gui);
252 gl_util_combo_box_add_text_model (GTK_COMBO_BOX (dialog->priv->type_combo));
254 dialog->priv->label = label;
256 dialog->priv->merge = gl_label_get_merge (dialog->priv->label);
257 description = gl_merge_get_description (dialog->priv->merge);
258 src_type = gl_merge_get_src_type (dialog->priv->merge);
259 src = gl_merge_get_src (dialog->priv->merge);
261 /* --- Window title --- */
262 name = gl_label_get_short_name (label);
263 title = g_strdup_printf ("%s %s", name, _("Merge Properties"));
264 gtk_window_set_title (GTK_WINDOW (dialog), title);
268 texts = gl_merge_get_descriptions ();
269 gl_debug (DEBUG_MERGE, "DESCRIPTIONS:");
273 for (p=texts; p!=NULL; p=p->next) {
274 gl_debug (DEBUG_MERGE, " \"%s\"", p->data);
277 gl_util_combo_box_set_strings (GTK_COMBO_BOX (dialog->priv->type_combo),
279 gl_merge_free_descriptions (&texts);
280 gl_util_combo_box_set_active_text (GTK_COMBO_BOX (dialog->priv->type_combo),
282 g_signal_connect (G_OBJECT (dialog->priv->type_combo), "changed",
283 G_CALLBACK (type_changed_cb), dialog);
285 gl_debug (DEBUG_MERGE, "Src_type = %d", src_type);
287 case GL_MERGE_SRC_IS_FILE:
288 dialog->priv->src_entry =
289 gtk_file_chooser_button_new (_("Select merge-database source"),
290 GTK_FILE_CHOOSER_ACTION_OPEN);
291 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog->priv->src_entry),
293 g_signal_connect (G_OBJECT (dialog->priv->src_entry),
295 G_CALLBACK (src_changed_cb), dialog);
298 dialog->priv->src_entry = gtk_label_new (_("N/A"));
299 gtk_misc_set_alignment (GTK_MISC (dialog->priv->src_entry), 0.0, 0.5);
302 gtk_box_pack_start (GTK_BOX (dialog->priv->location_vbox),
303 dialog->priv->src_entry, FALSE, FALSE, 0);
304 gtk_widget_show_all (GTK_WIDGET (dialog->priv->location_vbox));
306 dialog->priv->store = gtk_tree_store_new (N_COLUMNS,
307 G_TYPE_BOOLEAN, /* Record selector */
308 G_TYPE_STRING, /* Record/Field name */
309 G_TYPE_STRING, /* Field value */
310 G_TYPE_BOOLEAN, /* Is Record? */
311 G_TYPE_POINTER /* Pointer to record */);
312 load_tree (dialog->priv->store, dialog->priv->merge);
314 gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->priv->treeview),
315 GTK_TREE_MODEL (dialog->priv->store));
317 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (dialog->priv->treeview),
319 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->treeview));
320 gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
321 renderer = gtk_cell_renderer_toggle_new ();
322 g_signal_connect (G_OBJECT (renderer), "toggled",
323 G_CALLBACK (record_select_toggled_cb), dialog->priv->store);
324 column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
325 "active", SELECT_COLUMN,
326 "visible", IS_RECORD_COLUMN,
328 gtk_tree_view_column_set_clickable (column, TRUE);
329 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
330 renderer = gtk_cell_renderer_text_new ();
331 gtk_object_set (GTK_OBJECT (renderer), "yalign", 0.0, NULL);
332 column = gtk_tree_view_column_new_with_attributes (_("Record/Field"), renderer,
333 "text", RECORD_FIELD_COLUMN,
335 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
336 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
337 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
338 renderer = gtk_cell_renderer_text_new ();
339 gtk_object_set (GTK_OBJECT (renderer), "yalign", 0.0, NULL);
340 column = gtk_tree_view_column_new_with_attributes (_("Data"), renderer,
341 "text", VALUE_COLUMN,
343 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
344 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
346 g_signal_connect (G_OBJECT (dialog->priv->select_all_button),
348 G_CALLBACK (select_all_button_clicked_cb), dialog);
350 g_signal_connect (G_OBJECT (dialog->priv->unselect_all_button),
352 G_CALLBACK (unselect_all_button_clicked_cb), dialog);
356 g_free (description);
358 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
360 gl_debug (DEBUG_MERGE, "END");
363 /*--------------------------------------------------------------------------*/
364 /* PRIVATE. type "changed" callback. */
365 /*--------------------------------------------------------------------------*/
367 type_changed_cb (GtkWidget *widget,
368 glMergePropertiesDialog *dialog)
373 glMergeSrcType src_type;
375 gl_debug (DEBUG_MERGE, "START");
377 description = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->priv->type_combo));
378 name = gl_merge_description_to_name (description);
380 src = gl_merge_get_src (dialog->priv->merge); /* keep current src if possible */
382 gl_debug (DEBUG_MERGE, "Saving src = \"%s\"", src);
383 g_free (dialog->priv->saved_src);
384 dialog->priv->saved_src = src;
387 if (dialog->priv->merge != NULL) {
388 g_object_unref (G_OBJECT(dialog->priv->merge));
390 dialog->priv->merge = gl_merge_new (name);
392 gtk_widget_destroy (dialog->priv->src_entry);
393 src_type = gl_merge_get_src_type (dialog->priv->merge);
395 case GL_MERGE_SRC_IS_FILE:
396 dialog->priv->src_entry =
397 gtk_file_chooser_button_new (_("Select merge-database source"),
398 GTK_FILE_CHOOSER_ACTION_OPEN);
399 if (dialog->priv->saved_src != NULL) {
400 gl_debug (DEBUG_MERGE, "Setting src = \"%s\"", dialog->priv->saved_src);
401 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog->priv->src_entry),
402 dialog->priv->saved_src);
403 gl_merge_set_src (dialog->priv->merge, dialog->priv->saved_src);
405 g_signal_connect (G_OBJECT (dialog->priv->src_entry),
407 G_CALLBACK (src_changed_cb), dialog);
409 case GL_MERGE_SRC_IS_FIXED:
410 dialog->priv->src_entry = gtk_label_new (_("Fixed"));
411 gtk_misc_set_alignment (GTK_MISC (dialog->priv->src_entry), 0.0, 0.5);
413 gl_debug (DEBUG_MERGE, "Setting src = \"%s\"", dialog->priv->saved_src);
414 gl_merge_set_src (dialog->priv->merge, "Fixed");
417 dialog->priv->src_entry = gtk_label_new (_("N/A"));
418 gtk_misc_set_alignment (GTK_MISC (dialog->priv->src_entry), 0.0, 0.5);
421 gtk_box_pack_start( GTK_BOX (dialog->priv->location_vbox),
422 dialog->priv->src_entry, FALSE, FALSE, 0);
423 gtk_widget_show_all (dialog->priv->location_vbox);
425 load_tree (dialog->priv->store, dialog->priv->merge);
427 g_free (description);
430 gl_debug (DEBUG_MERGE, "END");
433 /*--------------------------------------------------------------------------*/
434 /* PRIVATE. source "changed" callback. */
435 /*--------------------------------------------------------------------------*/
437 src_changed_cb (GtkWidget *widget,
438 glMergePropertiesDialog *dialog)
440 gchar *src, *orig_src;
442 gl_debug (DEBUG_MERGE, "START");
444 orig_src = gl_merge_get_src (dialog->priv->merge);
445 src = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog->priv->src_entry));
447 gl_debug (DEBUG_MERGE, "orig=\"%s\", new=\"%s\"\n", orig_src, src);
449 if (((orig_src == NULL) && (src != NULL)) ||
450 ((orig_src != NULL) && (src == NULL)) ||
451 ((orig_src != NULL) && (src != NULL) && strcmp (src, orig_src)))
453 gl_merge_set_src (dialog->priv->merge, src);
454 load_tree (dialog->priv->store, dialog->priv->merge);
461 gl_debug (DEBUG_MERGE, "END");
464 /*--------------------------------------------------------------------------*/
465 /* PRIVATE. response callback. */
466 /*--------------------------------------------------------------------------*/
468 response_cb (glMergePropertiesDialog *dialog,
472 gl_debug (DEBUG_MERGE, "START");
476 case GTK_RESPONSE_OK:
477 gl_label_set_merge (dialog->priv->label, dialog->priv->merge);
478 gtk_widget_hide (GTK_WIDGET (dialog));
480 case GTK_RESPONSE_CANCEL:
481 /* Let the dialog get rebuilt next time to recover state. */
482 gtk_widget_destroy (GTK_WIDGET (dialog));
484 case GTK_RESPONSE_DELETE_EVENT:
487 g_print ("response = %d", response);
488 g_assert_not_reached ();
491 gl_debug (DEBUG_MERGE, "END");
494 /*--------------------------------------------------------------------------*/
495 /* PRIVATE. Load tree store from merge data. */
496 /*--------------------------------------------------------------------------*/
498 load_tree (GtkTreeStore *store,
501 const GList *record_list;
502 GList *p_rec, *p_field;
503 glMergeRecord *record;
505 GtkTreeIter iter1, iter2;
507 gchar *primary_value;
509 gl_debug (DEBUG_MERGE, "START");
511 gtk_tree_store_clear (store);
513 primary_key = gl_merge_get_primary_key (merge);
514 record_list = gl_merge_get_record_list (merge);
516 for ( p_rec=(GList *)record_list; p_rec!=NULL; p_rec=p_rec->next ) {
517 record = (glMergeRecord *)p_rec->data;
519 primary_value = gl_merge_eval_key (record, primary_key);
521 gtk_tree_store_append (store, &iter1, NULL);
522 gtk_tree_store_set (store, &iter1,
523 SELECT_COLUMN, record->select_flag,
524 RECORD_FIELD_COLUMN, primary_value,
525 IS_RECORD_COLUMN, TRUE,
529 g_free (primary_value);
531 for ( p_field=record->field_list; p_field!=NULL; p_field=p_field->next ) {
532 field = (glMergeField *)p_field->data;
534 gtk_tree_store_append (store, &iter2, &iter1);
535 gtk_tree_store_set (store, &iter2,
536 RECORD_FIELD_COLUMN, field->key,
537 VALUE_COLUMN, field->value,
538 IS_RECORD_COLUMN, FALSE,
543 g_free (primary_key);
545 gl_debug (DEBUG_MERGE, "END");
548 /*--------------------------------------------------------------------------*/
549 /* PRIVATE. Record select toggled. */
550 /*--------------------------------------------------------------------------*/
552 record_select_toggled_cb (GtkCellRendererToggle *cell,
558 glMergeRecord *record;
560 gl_debug (DEBUG_MERGE, "START");
562 /* get toggled iter */
563 path = gtk_tree_path_new_from_string (path_str);
564 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
566 /* get current data */
567 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
568 DATA_COLUMN, &record,
571 /* toggle the select flag within the record */
572 record->select_flag ^= 1;
574 /* set new value in store */
575 gtk_tree_store_set (store, &iter,
576 SELECT_COLUMN, record->select_flag,
580 gtk_tree_path_free (path);
582 gl_debug (DEBUG_MERGE, "END");
585 /*--------------------------------------------------------------------------*/
586 /* PRIVATE. "Select All" button callback. */
587 /*--------------------------------------------------------------------------*/
589 select_all_button_clicked_cb (GtkWidget *widget,
590 glMergePropertiesDialog *dialog)
592 GtkTreeModel *store = GTK_TREE_MODEL (dialog->priv->store);
594 glMergeRecord *record;
597 gl_debug (DEBUG_MERGE, "START");
599 for ( good = gtk_tree_model_get_iter_first (store, &iter);
601 good = gtk_tree_model_iter_next (store, &iter) )
604 /* get current data */
605 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
606 DATA_COLUMN, &record,
610 /* Set select flag within the record */
611 record->select_flag = TRUE;
613 /* set new value in store */
614 gtk_tree_store_set (GTK_TREE_STORE (store), &iter,
615 SELECT_COLUMN, record->select_flag,
620 gl_debug (DEBUG_MERGE, "END");
623 /*--------------------------------------------------------------------------*/
624 /* PRIVATE. "Unselect All" button callback. */
625 /*--------------------------------------------------------------------------*/
627 unselect_all_button_clicked_cb (GtkWidget *widget,
628 glMergePropertiesDialog *dialog)
630 GtkTreeModel *store = GTK_TREE_MODEL (dialog->priv->store);
632 glMergeRecord *record;
635 gl_debug (DEBUG_MERGE, "START");
637 for ( good = gtk_tree_model_get_iter_first (store, &iter);
639 good = gtk_tree_model_iter_next (store, &iter) )
642 /* get current data */
643 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
644 DATA_COLUMN, &record,
648 /* Set select flag within the record */
649 record->select_flag = FALSE;
651 /* set new value in store */
652 gtk_tree_store_set (GTK_TREE_STORE (store), &iter,
653 SELECT_COLUMN, record->select_flag,
658 gl_debug (DEBUG_MERGE, "END");