2 * merge-properties-dialog.c
3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
7 * gLabels is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * gLabels is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
23 #include "merge-properties-dialog.h"
25 #include <glib/gi18n.h>
31 #include "combo-util.h"
32 #include "builder-util.h"
37 /*===========================================*/
38 /* Private data types */
39 /*===========================================*/
41 struct _glMergePropertiesDialogPrivate {
48 GtkWidget *type_combo_hbox;
49 GtkWidget *type_combo;
50 GtkWidget *location_vbox;
56 GtkWidget *select_all_button;
57 GtkWidget *unselect_all_button;
71 /* Invisible columns */
73 DATA_COLUMN, /* points to glMergeRecord */
79 /*===========================================*/
81 /*===========================================*/
84 /*===========================================*/
85 /* Local function prototypes */
86 /*===========================================*/
88 static void gl_merge_properties_dialog_finalize (GObject *object);
89 static void gl_merge_properties_dialog_construct (glMergePropertiesDialog *dialog,
93 static void type_changed_cb (GtkWidget *widget,
94 glMergePropertiesDialog *dialog);
96 static void src_changed_cb (GtkWidget *widget,
97 glMergePropertiesDialog *dialog);
99 static void response_cb (glMergePropertiesDialog *dialog,
103 static void load_tree (GtkTreeStore *store,
106 static void record_select_toggled_cb (GtkCellRendererToggle *cell,
108 GtkTreeStore *store);
110 static void select_all_button_clicked_cb (GtkWidget *widget,
111 glMergePropertiesDialog *dialog);
113 static void unselect_all_button_clicked_cb (GtkWidget *widget,
114 glMergePropertiesDialog *dialog);
117 /*****************************************************************************/
118 /* Boilerplate object stuff. */
119 /*****************************************************************************/
120 G_DEFINE_TYPE (glMergePropertiesDialog, gl_merge_properties_dialog, GTK_TYPE_DIALOG)
123 /*****************************************************************************/
124 /* Class Init Function. */
125 /*****************************************************************************/
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 /*****************************************************************************/
140 /* Object Instance Init Function. */
141 /*****************************************************************************/
143 gl_merge_properties_dialog_init (glMergePropertiesDialog *dialog)
145 gchar *builder_filename;
147 static gchar *object_ids[] = { "merge_properties_vbox", NULL };
148 GError *error = NULL;
150 GtkWidget *merge_properties_vbox;
152 gl_debug (DEBUG_MERGE, "START");
154 dialog->priv = g_new0 (glMergePropertiesDialogPrivate, 1);
156 vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
158 gtk_dialog_add_button (GTK_DIALOG (dialog),
159 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
160 dialog->priv->ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
161 GTK_STOCK_OK, GTK_RESPONSE_OK);
163 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
165 builder = gtk_builder_new ();
166 builder_filename = g_build_filename (GLABELS_DATA_DIR, "ui", "merge-properties-dialog.ui", NULL);
167 gtk_builder_add_objects_from_file (builder, builder_filename, object_ids, &error);
168 g_free (builder_filename);
170 g_critical ("%s\n\ngLabels may not be installed correctly!", error->message);
171 g_error_free (error);
175 gl_builder_util_get_widgets (builder,
176 "merge_properties_vbox", &merge_properties_vbox,
177 "type_combo_hbox", &dialog->priv->type_combo_hbox,
178 "location_vbox", &dialog->priv->location_vbox,
179 "treeview", &dialog->priv->treeview,
180 "select_all_button", &dialog->priv->select_all_button,
181 "unselect_all_button", &dialog->priv->unselect_all_button,
184 gtk_container_add (GTK_CONTAINER (vbox), merge_properties_vbox);
185 dialog->priv->builder = builder;
187 dialog->priv->type_combo = gtk_combo_box_text_new ();
188 gtk_box_pack_start (GTK_BOX (dialog->priv->type_combo_hbox), dialog->priv->type_combo, TRUE, TRUE, 0);
189 gtk_widget_show_all (GTK_WIDGET (dialog->priv->type_combo));
191 gl_debug (DEBUG_MERGE, "END");
195 /*****************************************************************************/
196 /* Finalize Function. */
197 /*****************************************************************************/
199 gl_merge_properties_dialog_finalize (GObject *object)
201 glMergePropertiesDialog* dialog = GL_MERGE_PROPERTIES_DIALOG (object);
203 gl_debug (DEBUG_MERGE, "START");
205 g_return_if_fail (object != NULL);
206 g_return_if_fail (GL_IS_MERGE_PROPERTIES_DIALOG (dialog));
207 g_return_if_fail (dialog->priv != NULL);
209 if (dialog->priv->merge != NULL) {
210 g_object_unref (G_OBJECT (dialog->priv->merge));
212 if (dialog->priv->builder != NULL) {
213 g_object_unref (G_OBJECT (dialog->priv->builder));
215 g_free (dialog->priv);
217 G_OBJECT_CLASS (gl_merge_properties_dialog_parent_class)->finalize (object);
218 gl_debug (DEBUG_MERGE, "END");
222 /*****************************************************************************/
223 /* NEW merge properties dialog. */
224 /*****************************************************************************/
226 gl_merge_properties_dialog_new (glLabel *label,
231 gl_debug (DEBUG_MERGE, "START");
233 dialog = GTK_WIDGET (g_object_new (GL_TYPE_MERGE_PROPERTIES_DIALOG, NULL));
235 gl_merge_properties_dialog_construct (GL_MERGE_PROPERTIES_DIALOG (dialog),
238 gl_debug (DEBUG_MERGE, "END");
244 /*--------------------------------------------------------------------------*/
245 /* PRIVATE. Create merge widgets. */
246 /*--------------------------------------------------------------------------*/
248 gl_merge_properties_dialog_construct (glMergePropertiesDialog *dialog,
253 glMergeSrcType src_type;
257 GtkCellRenderer *renderer;
258 GtkTreeViewColumn *column;
259 GtkTreeSelection *selection;
261 gl_debug (DEBUG_MERGE, "START");
263 g_return_if_fail (GL_IS_MERGE_PROPERTIES_DIALOG (dialog));
264 g_return_if_fail (dialog->priv != NULL);
267 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(window));
268 gtk_window_set_destroy_with_parent (GTK_WINDOW(dialog), TRUE);
271 dialog->priv->label = label;
273 dialog->priv->merge = gl_label_get_merge (dialog->priv->label);
274 description = gl_merge_get_description (dialog->priv->merge);
275 src_type = gl_merge_get_src_type (dialog->priv->merge);
276 src = gl_merge_get_src (dialog->priv->merge);
278 /* --- Window title --- */
279 name = gl_label_get_short_name (label);
280 title = g_strdup_printf ("%s %s", name, _("Merge Properties"));
281 gtk_window_set_title (GTK_WINDOW (dialog), title);
285 texts = gl_merge_get_descriptions ();
286 gl_debug (DEBUG_MERGE, "DESCRIPTIONS:");
290 for (p=texts; p!=NULL; p=p->next) {
291 gl_debug (DEBUG_MERGE, " \"%s\"", p->data);
294 gl_combo_util_set_strings (GTK_COMBO_BOX_TEXT (dialog->priv->type_combo), texts);
295 gl_merge_free_descriptions (&texts);
296 gl_combo_util_set_active_text (GTK_COMBO_BOX (dialog->priv->type_combo), description);
297 g_signal_connect (G_OBJECT (dialog->priv->type_combo), "changed",
298 G_CALLBACK (type_changed_cb), dialog);
300 gl_debug (DEBUG_MERGE, "Src_type = %d", src_type);
302 case GL_MERGE_SRC_IS_FILE:
303 dialog->priv->src_entry =
304 gtk_file_chooser_button_new (_("Select merge-database source"),
305 GTK_FILE_CHOOSER_ACTION_OPEN);
306 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog->priv->src_entry),
308 gtk_file_chooser_button_set_focus_on_click (GTK_FILE_CHOOSER_BUTTON (dialog->priv->src_entry),
310 g_signal_connect (G_OBJECT (dialog->priv->src_entry),
312 G_CALLBACK (src_changed_cb), dialog);
315 dialog->priv->src_entry = gtk_label_new (_("N/A"));
316 gtk_misc_set_alignment (GTK_MISC (dialog->priv->src_entry), 0.0, 0.5);
319 gtk_box_pack_start (GTK_BOX (dialog->priv->location_vbox),
320 dialog->priv->src_entry, FALSE, FALSE, 0);
321 gtk_widget_show_all (GTK_WIDGET (dialog->priv->location_vbox));
323 dialog->priv->store = gtk_tree_store_new (N_COLUMNS,
324 G_TYPE_BOOLEAN, /* Record selector */
325 G_TYPE_STRING, /* Record/Field name */
326 G_TYPE_STRING, /* Field value */
327 G_TYPE_BOOLEAN, /* Is Record? */
328 G_TYPE_POINTER /* Pointer to record */);
329 load_tree (dialog->priv->store, dialog->priv->merge);
331 gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->priv->treeview),
332 GTK_TREE_MODEL (dialog->priv->store));
334 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (dialog->priv->treeview),
336 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->treeview));
337 gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
338 renderer = gtk_cell_renderer_toggle_new ();
339 g_signal_connect (G_OBJECT (renderer), "toggled",
340 G_CALLBACK (record_select_toggled_cb), dialog->priv->store);
341 column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
342 "active", SELECT_COLUMN,
343 "visible", IS_RECORD_COLUMN,
345 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
346 renderer = gtk_cell_renderer_text_new ();
347 g_object_set (G_OBJECT (renderer), "yalign", 0.0, NULL);
348 column = gtk_tree_view_column_new_with_attributes (_("Record/Field"), renderer,
349 "text", RECORD_FIELD_COLUMN,
351 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
352 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
353 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
354 renderer = gtk_cell_renderer_text_new ();
355 g_object_set (G_OBJECT (renderer), "yalign", 0.0, NULL);
356 column = gtk_tree_view_column_new_with_attributes (_("Data"), renderer,
357 "text", VALUE_COLUMN,
359 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
360 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->treeview), column);
362 g_signal_connect (G_OBJECT (dialog->priv->select_all_button),
364 G_CALLBACK (select_all_button_clicked_cb), dialog);
366 g_signal_connect (G_OBJECT (dialog->priv->unselect_all_button),
368 G_CALLBACK (unselect_all_button_clicked_cb), dialog);
372 g_free (description);
374 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
376 gtk_widget_grab_focus (dialog->priv->ok_button);
377 gtk_widget_grab_default (dialog->priv->ok_button);
379 g_signal_connect(G_OBJECT (dialog), "response",
380 G_CALLBACK (response_cb), NULL);
382 gl_debug (DEBUG_MERGE, "END");
386 /*--------------------------------------------------------------------------*/
387 /* PRIVATE. type "changed" callback. */
388 /*--------------------------------------------------------------------------*/
390 type_changed_cb (GtkWidget *widget,
391 glMergePropertiesDialog *dialog)
396 glMergeSrcType src_type;
398 gl_debug (DEBUG_MERGE, "START");
400 description = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (dialog->priv->type_combo));
401 name = gl_merge_description_to_name (description);
403 src = gl_merge_get_src (dialog->priv->merge); /* keep current src if possible */
405 gl_debug (DEBUG_MERGE, "Saving src = \"%s\"", src);
406 g_free (dialog->priv->saved_src);
407 dialog->priv->saved_src = src;
410 if (dialog->priv->merge != NULL) {
411 g_object_unref (G_OBJECT(dialog->priv->merge));
413 dialog->priv->merge = gl_merge_new (name);
415 gtk_widget_destroy (dialog->priv->src_entry);
416 src_type = gl_merge_get_src_type (dialog->priv->merge);
418 case GL_MERGE_SRC_IS_FILE:
419 dialog->priv->src_entry =
420 gtk_file_chooser_button_new (_("Select merge-database source"),
421 GTK_FILE_CHOOSER_ACTION_OPEN);
422 gtk_file_chooser_button_set_focus_on_click (GTK_FILE_CHOOSER_BUTTON (dialog->priv->src_entry),
424 if (dialog->priv->saved_src != NULL) {
425 gl_debug (DEBUG_MERGE, "Setting src = \"%s\"", dialog->priv->saved_src);
426 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog->priv->src_entry),
427 dialog->priv->saved_src);
428 gl_merge_set_src (dialog->priv->merge, dialog->priv->saved_src);
430 g_signal_connect (G_OBJECT (dialog->priv->src_entry),
432 G_CALLBACK (src_changed_cb), dialog);
434 case GL_MERGE_SRC_IS_FIXED:
435 /* Translators: "Fixed" here means that for the given document-merge method, there are
436 * no further choices to further define the source of data. E.g. if you select the
437 * evolution-data-server, there are no further choices -- the source is "Fixed."
439 dialog->priv->src_entry = gtk_label_new (_("Fixed"));
440 gtk_misc_set_alignment (GTK_MISC (dialog->priv->src_entry), 0.0, 0.5);
442 gl_debug (DEBUG_MERGE, "Setting src = \"%s\"", dialog->priv->saved_src);
443 gl_merge_set_src (dialog->priv->merge, "Fixed");
446 dialog->priv->src_entry = gtk_label_new (_("N/A"));
447 gtk_misc_set_alignment (GTK_MISC (dialog->priv->src_entry), 0.0, 0.5);
450 gtk_box_pack_start( GTK_BOX (dialog->priv->location_vbox),
451 dialog->priv->src_entry, FALSE, FALSE, 0);
452 gtk_widget_show_all (dialog->priv->location_vbox);
454 load_tree (dialog->priv->store, dialog->priv->merge);
456 g_free (description);
459 gl_debug (DEBUG_MERGE, "END");
463 /*--------------------------------------------------------------------------*/
464 /* PRIVATE. source "changed" callback. */
465 /*--------------------------------------------------------------------------*/
467 src_changed_cb (GtkWidget *widget,
468 glMergePropertiesDialog *dialog)
470 gchar *src, *orig_src;
472 gl_debug (DEBUG_MERGE, "START");
474 orig_src = gl_merge_get_src (dialog->priv->merge);
475 src = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog->priv->src_entry));
477 gl_debug (DEBUG_MERGE, "orig=\"%s\", new=\"%s\"\n", orig_src, src);
479 if (((orig_src == NULL) && (src != NULL)) ||
480 ((orig_src != NULL) && (src == NULL)) ||
481 ((orig_src != NULL) && (src != NULL) && strcmp (src, orig_src)))
483 gl_merge_set_src (dialog->priv->merge, src);
484 load_tree (dialog->priv->store, dialog->priv->merge);
491 gl_debug (DEBUG_MERGE, "END");
495 /*--------------------------------------------------------------------------*/
496 /* PRIVATE. response callback. */
497 /*--------------------------------------------------------------------------*/
499 response_cb (glMergePropertiesDialog *dialog,
503 gl_debug (DEBUG_MERGE, "START");
507 case GTK_RESPONSE_OK:
508 gl_label_set_merge (dialog->priv->label, dialog->priv->merge, TRUE);
509 gtk_widget_hide (GTK_WIDGET (dialog));
511 case GTK_RESPONSE_CANCEL:
512 /* Let the dialog get rebuilt next time to recover state. */
513 gtk_widget_destroy (GTK_WIDGET (dialog));
515 case GTK_RESPONSE_DELETE_EVENT:
518 g_print ("response = %d", response);
519 g_assert_not_reached ();
522 gl_debug (DEBUG_MERGE, "END");
526 /*--------------------------------------------------------------------------*/
527 /* PRIVATE. Load tree store from merge data. */
528 /*--------------------------------------------------------------------------*/
530 load_tree (GtkTreeStore *store,
533 const GList *record_list;
534 GList *p_rec, *p_field;
535 glMergeRecord *record;
537 GtkTreeIter iter1, iter2;
539 gchar *primary_value;
541 gl_debug (DEBUG_MERGE, "START");
543 gtk_tree_store_clear (store);
545 primary_key = gl_merge_get_primary_key (merge);
546 record_list = gl_merge_get_record_list (merge);
548 for ( p_rec=(GList *)record_list; p_rec!=NULL; p_rec=p_rec->next ) {
549 record = (glMergeRecord *)p_rec->data;
551 primary_value = gl_merge_eval_key (record, primary_key);
553 gtk_tree_store_append (store, &iter1, NULL);
554 gtk_tree_store_set (store, &iter1,
555 SELECT_COLUMN, record->select_flag,
556 RECORD_FIELD_COLUMN, primary_value,
557 IS_RECORD_COLUMN, TRUE,
561 g_free (primary_value);
563 for ( p_field=record->field_list; p_field!=NULL; p_field=p_field->next ) {
564 field = (glMergeField *)p_field->data;
566 gtk_tree_store_append (store, &iter2, &iter1);
567 gtk_tree_store_set (store, &iter2,
568 RECORD_FIELD_COLUMN, field->key,
569 VALUE_COLUMN, field->value,
570 IS_RECORD_COLUMN, FALSE,
575 g_free (primary_key);
577 gl_debug (DEBUG_MERGE, "END");
581 /*--------------------------------------------------------------------------*/
582 /* PRIVATE. Record select toggled. */
583 /*--------------------------------------------------------------------------*/
585 record_select_toggled_cb (GtkCellRendererToggle *cell,
591 glMergeRecord *record;
593 gl_debug (DEBUG_MERGE, "START");
595 /* get toggled iter */
596 path = gtk_tree_path_new_from_string (path_str);
597 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
599 /* get current data */
600 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
601 DATA_COLUMN, &record,
604 /* toggle the select flag within the record */
605 record->select_flag ^= 1;
607 /* set new value in store */
608 gtk_tree_store_set (store, &iter,
609 SELECT_COLUMN, record->select_flag,
613 gtk_tree_path_free (path);
615 gl_debug (DEBUG_MERGE, "END");
619 /*--------------------------------------------------------------------------*/
620 /* PRIVATE. "Select All" button callback. */
621 /*--------------------------------------------------------------------------*/
623 select_all_button_clicked_cb (GtkWidget *widget,
624 glMergePropertiesDialog *dialog)
626 GtkTreeModel *store = GTK_TREE_MODEL (dialog->priv->store);
628 glMergeRecord *record;
631 gl_debug (DEBUG_MERGE, "START");
633 for ( good = gtk_tree_model_get_iter_first (store, &iter);
635 good = gtk_tree_model_iter_next (store, &iter) )
638 /* get current data */
639 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
640 DATA_COLUMN, &record,
644 /* Set select flag within the record */
645 record->select_flag = TRUE;
647 /* set new value in store */
648 gtk_tree_store_set (GTK_TREE_STORE (store), &iter,
649 SELECT_COLUMN, record->select_flag,
654 gl_debug (DEBUG_MERGE, "END");
658 /*--------------------------------------------------------------------------*/
659 /* PRIVATE. "Unselect All" button callback. */
660 /*--------------------------------------------------------------------------*/
662 unselect_all_button_clicked_cb (GtkWidget *widget,
663 glMergePropertiesDialog *dialog)
665 GtkTreeModel *store = GTK_TREE_MODEL (dialog->priv->store);
667 glMergeRecord *record;
670 gl_debug (DEBUG_MERGE, "START");
672 for ( good = gtk_tree_model_get_iter_first (store, &iter);
674 good = gtk_tree_model_iter_next (store, &iter) )
677 /* get current data */
678 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
679 DATA_COLUMN, &record,
683 /* Set select flag within the record */
684 record->select_flag = FALSE;
686 /* set new value in store */
687 gtk_tree_store_set (GTK_TREE_STORE (store), &iter,
688 SELECT_COLUMN, record->select_flag,
693 gl_debug (DEBUG_MERGE, "END");
699 * Local Variables: -- emacs
701 * c-basic-offset: 8 -- emacs
702 * tab-width: 8 -- emacs
703 * indent-tabs-mode: nil -- emacs