1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
4 * This file is part of HomeBank.
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty ofdeftransaction_amountchanged
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 /****************************************************************************/
27 /****************************************************************************/
36 /* our global datas */
37 extern struct HomeBank
*GLOBALS
;
38 extern struct Preferences
*PREFS
;
41 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
45 ui_tag_combobox_populate(GtkComboBoxText
*combobox
)
50 hbtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(combobox
), 0, "----");
51 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox
), 0);
53 ltag
= list
= tag_glist_sorted(1);
56 Tag
*item
= list
->data
;
58 DB( g_print(" populate: %d\n", item
->key
) );
60 hbtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(combobox
), item
->key
, item
->name
);
61 list
= g_list_next(list
);
70 ui_tag_combobox_new(GtkWidget
*label
)
74 combobox
= hbtk_combo_box_new(label
);
79 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
83 ui_tag_listview_toggled_cb (GtkCellRendererToggle
*cell
,
87 GtkTreeModel
*model
= (GtkTreeModel
*)data
;
89 GtkTreePath
*path
= gtk_tree_path_new_from_string (path_str
);
92 /* get toggled iter */
93 gtk_tree_model_get_iter (model
, &iter
, path
);
94 gtk_tree_model_get (model
, &iter
, LST_DEFTAG_TOGGLE
, &fixed
, -1);
96 /* do something with the value */
100 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
, LST_DEFTAG_TOGGLE
, fixed
, -1);
103 gtk_tree_path_free (path
);
107 ui_tag_listview_compare_func (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
)
110 Tag
*entry1
, *entry2
;
111 //gchar *name1, *name2;
113 gtk_tree_model_get(model
, a
, LST_DEFTAG_DATAS
, &entry1
, -1);
114 gtk_tree_model_get(model
, b
, LST_DEFTAG_DATAS
, &entry2
, -1);
116 retval
= hb_string_utf8_compare(entry1
->name
, entry2
->name
);
123 ui_tag_listview_name_cell_data_function (GtkTreeViewColumn
*col
,
124 GtkCellRenderer
*renderer
,
135 gtk_tree_model_get(model
, iter
, LST_DEFTAG_DATAS
, &entry
, -1);
136 if(entry
->name
== NULL
)
137 name
= _("(none)"); // can never occurs !
142 string
= g_strdup_printf ("[%d] %s", entry
->key
, name
);
143 g_object_set(renderer
, "text", string
, NULL
);
146 g_object_set(renderer
, "text", name
, NULL
);
153 /* = = = = = = = = = = = = = = = = */
158 * Add a single element (useful for dynamics add)
164 ui_tag_listview_add(GtkTreeView
*treeview
, Tag
*item
)
166 if( item
->name
!= NULL
)
171 model
= gtk_tree_view_get_model(treeview
);
173 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
174 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
175 LST_DEFTAG_TOGGLE
, FALSE
,
176 LST_DEFTAG_DATAS
, item
,
179 gtk_tree_selection_select_iter (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)), &iter
);
185 ui_tag_listview_get_selected_key(GtkTreeView
*treeview
)
187 GtkTreeSelection
*selection
;
191 selection
= gtk_tree_view_get_selection(treeview
);
192 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
196 gtk_tree_model_get(model
, &iter
, LST_DEFTAG_DATAS
, &item
, -1);
205 ui_tag_listview_remove_selected(GtkTreeView
*treeview
)
207 GtkTreeSelection
*selection
;
211 selection
= gtk_tree_view_get_selection(treeview
);
212 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
214 gtk_list_store_remove(GTK_LIST_STORE(model
), &iter
);
219 void ui_tag_listview_populate(GtkWidget
*view
, gint insert_type
)
225 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
227 gtk_list_store_clear (GTK_LIST_STORE(model
));
229 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
230 gtk_tree_view_set_model(GTK_TREE_VIEW(view
), NULL
); /* Detach model from view */
233 //g_hash_table_foreach(GLOBALS->h_tag, (GHFunc)ui_tag_listview_populate_ghfunc, model);
234 ltag
= list
= g_hash_table_get_values(GLOBALS
->h_tag
);
237 Tag
*item
= list
->data
;
239 DB( g_print(" populate: %d\n", item
->key
) );
241 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
242 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
243 LST_DEFTAG_TOGGLE
, FALSE
,
244 LST_DEFTAG_DATAS
, item
,
247 list
= g_list_next(list
);
251 gtk_tree_view_set_model(GTK_TREE_VIEW(view
), model
); /* Re-attach model to view */
252 g_object_unref(model
);
257 ui_tag_listview_new(gboolean withtoggle
)
261 GtkCellRenderer
*renderer
;
262 GtkTreeViewColumn
*column
;
265 store
= gtk_list_store_new(NUM_LST_DEFTAG
,
271 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
272 g_object_unref(store
);
274 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (treeview
), PREFS
->grid_lines
);
277 if( withtoggle
== TRUE
)
279 renderer
= gtk_cell_renderer_toggle_new ();
280 column
= gtk_tree_view_column_new_with_attributes (_("Visible"),
282 "active", LST_DEFTAG_TOGGLE
,
284 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
286 g_signal_connect (renderer
, "toggled",
287 G_CALLBACK (ui_tag_listview_toggled_cb
), store
);
292 column
= gtk_tree_view_column_new();
294 renderer
= gtk_cell_renderer_text_new ();
295 g_object_set(renderer
,
296 "ellipsize", PANGO_ELLIPSIZE_END
,
297 "ellipsize-set", TRUE
,
300 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
301 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_tag_listview_name_cell_data_function
, GINT_TO_POINTER(LST_DEFTAG_DATAS
), NULL
);
303 gtk_tree_view_column_set_resizable(column
, TRUE
);
304 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
307 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview
), FALSE
);
308 gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview
), TRUE
);
310 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store
), ui_tag_listview_compare_func
, NULL
, NULL
);
311 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
, GTK_SORT_ASCENDING
);
318 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
322 * ui_tag_manage_dialog_add:
326 ui_tag_manage_dialog_add(GtkWidget
*widget
, gpointer user_data
)
328 struct ui_tag_manage_dialog_data
*data
;
332 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
333 DB( g_print("(defayee) add (data=%p)\n", data
) );
335 name
= (gchar
*)gtk_entry_get_text(GTK_ENTRY(data
->ST_name
));
337 item
= da_tag_malloc ();
338 item
->name
= g_strdup(name
);
340 g_strstrip(item
->name
);
342 if( strlen(item
->name
) > 0 )
344 if( da_tag_append(item
) )
346 ui_tag_listview_add(GTK_TREE_VIEW(data
->LV_tag
), item
);
353 gtk_entry_set_text(GTK_ENTRY(data
->ST_name
), "");
357 static void ui_tag_manage_dialog_edit_entry_cb(GtkEditable
*editable
, gpointer user_data
)
359 GtkDialog
*window
= user_data
;
362 buffer
= gtk_entry_get_text(GTK_ENTRY(editable
));
363 gtk_dialog_set_response_sensitive(GTK_DIALOG(window
), GTK_RESPONSE_ACCEPT
, strlen(buffer
) > 0 ? TRUE
: FALSE
);
367 static void ui_tag_manage_dialog_edit(GtkWidget
*dowidget
, gpointer user_data
)
369 struct ui_tag_manage_dialog_data
*data
;
370 GtkWidget
*dialog
, *content_area
, *content_grid
, *group_grid
;
371 GtkWidget
*label
, *widget
;
376 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(dowidget
, GTK_TYPE_WINDOW
)), "inst_data");
377 DB( g_print("(defayee) modify %p\n", data
) );
379 key
= ui_tag_listview_get_selected_key(GTK_TREE_VIEW(data
->LV_tag
));
384 item
= da_tag_get( key
);
386 dialog
= gtk_dialog_new_with_buttons (_("Edit..."),
387 GTK_WINDOW (data
->window
),
395 content_area
= gtk_dialog_get_content_area(GTK_DIALOG (dialog
));
397 content_grid
= gtk_grid_new();
398 gtk_grid_set_row_spacing (GTK_GRID (content_grid
), SPACING_LARGE
);
399 gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid
), GTK_ORIENTATION_VERTICAL
);
400 gtk_container_set_border_width (GTK_CONTAINER(content_grid
), SPACING_MEDIUM
);
401 gtk_box_pack_start (GTK_BOX (content_area
), content_grid
, TRUE
, TRUE
, 0);
405 group_grid
= gtk_grid_new ();
406 gtk_grid_set_row_spacing (GTK_GRID (group_grid
), SPACING_SMALL
);
407 gtk_grid_set_column_spacing (GTK_GRID (group_grid
), SPACING_MEDIUM
);
408 gtk_grid_attach (GTK_GRID (content_grid
), group_grid
, 0, crow
++, 1, 1);
410 //label = make_label_group(_("General"));
411 //gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
414 label
= make_label_widget(_("_Name:"));
415 gtk_grid_attach (GTK_GRID (group_grid
), label
, 1, row
, 1, 1);
416 widget
= gtk_entry_new();
418 gtk_widget_set_hexpand(widget
, TRUE
);
419 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 2, row
, 1, 1);
421 g_signal_connect (G_OBJECT (ST_name
), "changed", G_CALLBACK (ui_tag_manage_dialog_edit_entry_cb
), dialog
);
423 gtk_widget_show_all(content_grid
);
426 gtk_dialog_set_default_response(GTK_DIALOG( dialog
), GTK_RESPONSE_ACCEPT
);
429 gint result
= gtk_dialog_run (GTK_DIALOG (dialog
));
431 if(result
== GTK_RESPONSE_ACCEPT
)
435 // 1: manage renaming
436 name
= gtk_entry_get_text(GTK_ENTRY(ST_name
));
437 // ignore if item is empty
440 if( tag_rename(item
, name
) )
442 //to redraw the active entry
443 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_tag
));
448 ui_dialog_msg_infoerror(GTK_WINDOW(dialog
), GTK_MESSAGE_ERROR
,
450 _("Cannot rename this Tag,\n"
451 "from '%s' to '%s',\n"
452 "this name already exists."),
463 // cleanup and destroy
464 gtk_widget_destroy (dialog
);
471 ** delete the selected payee to our treeview and temp GList
473 static void ui_tag_manage_dialog_delete(GtkWidget
*widget
, gpointer user_data
)
475 struct ui_tag_manage_dialog_data
*data
;
481 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
482 DB( g_print("(ui_tag_manage_dialog) delete (data=%p)\n", data
) );
484 key
= ui_tag_listview_get_selected_key(GTK_TREE_VIEW(data
->LV_tag
));
488 gchar
*secondtext
= NULL
;
490 item
= da_tag_get(key
);
492 title
= g_strdup_printf (
493 _("Are you sure you want to permanently delete '%s'?"), item
->name
);
495 if( item
->usage_count
> 0 )
497 secondtext
= _("This payee is used.\n"
498 "Any transaction using that payee will be set to (no payee)");
501 result
= ui_dialog_msg_confirm_alert(
502 GTK_WINDOW(data
->window
),
510 if( result
== GTK_RESPONSE_OK
)
513 ui_tag_listview_remove_selected(GTK_TREE_VIEW(data
->LV_tag
));
522 static void ui_tag_manage_dialog_update(GtkWidget
*treeview
, gpointer user_data
)
524 struct ui_tag_manage_dialog_data
*data
;
528 DB( g_print("\n(ui_tag_manage_dialog) cursor changed\n") );
530 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
532 key
= ui_tag_listview_get_selected_key(GTK_TREE_VIEW(data
->LV_tag
));
534 sensitive
= (key
> 0) ? TRUE
: FALSE
;
535 gtk_widget_set_sensitive(data
->BT_edit
, sensitive
);
536 gtk_widget_set_sensitive(data
->BT_delete
, sensitive
);
544 static void ui_tag_manage_dialog_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
546 ui_tag_manage_dialog_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
549 static void ui_tag_manage_dialog_onRowActivated (GtkTreeView
*treeview
,
551 GtkTreeViewColumn
*col
,
557 DB( g_print("ui_tag_manage_dialog_onRowActivated()\n") );
560 model
= gtk_tree_view_get_model(treeview
);
561 gtk_tree_model_get_iter_first(model
, &iter
);
562 if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)), &iter
) == FALSE
)
564 ui_tag_manage_dialog_edit(GTK_WIDGET(treeview
), NULL
);
569 GtkWidget
*ui_tag_manage_dialog (void)
571 struct ui_tag_manage_dialog_data data
;
572 GtkWidget
*dialog
, *content
, *mainvbox
, *box
, *bbox
, *treeview
, *scrollwin
, *table
, *addreveal
;
575 dialog
= gtk_dialog_new_with_buttons (_("Manage Tags"),
576 GTK_WINDOW(GLOBALS
->mainwindow
),
578 _("_Close"), GTK_RESPONSE_ACCEPT
,
581 /*dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", TRUE, NULL);
582 gtk_window_set_title (GTK_WINDOW (dialog), _("Manage Tags"));
583 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW(GLOBALS->mainwindow));
584 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
586 //gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
588 data
.window
= dialog
;
591 //gtk_window_set_icon_name(GTK_WINDOW (dialog), ICONNAME_HB_TAG);
593 //set a nice dialog size
594 gtk_window_get_size(GTK_WINDOW(GLOBALS
->mainwindow
), &w
, &h
);
595 gtk_window_set_default_size (GTK_WINDOW(dialog
), -1, h
/PHI
);
598 //store our dialog private data
599 g_object_set_data(G_OBJECT(dialog
), "inst_data", (gpointer
)&data
);
600 DB( g_print("(ui_tag_manage_dialog) dialog=%p, inst_data=%p\n", dialog
, &data
) );
602 g_signal_connect (dialog
, "destroy",
603 G_CALLBACK (gtk_widget_destroyed
), &dialog
);
606 content
= gtk_dialog_get_content_area(GTK_DIALOG (dialog
));
607 mainvbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, SPACING_SMALL
);
608 gtk_box_pack_start (GTK_BOX (content
), mainvbox
, TRUE
, TRUE
, 0);
609 gtk_container_set_border_width (GTK_CONTAINER(mainvbox
), SPACING_MEDIUM
);
612 table
= gtk_grid_new ();
613 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_SMALL
);
614 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
615 gtk_box_pack_start (GTK_BOX (mainvbox
), table
, TRUE
, TRUE
, 0);
618 bbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, SPACING_MEDIUM
);
619 gtk_grid_attach (GTK_GRID (table
), bbox
, 0, row
, 2, 1);
621 //content = gtk_dialog_get_header_bar(GTK_DIALOG (dialog));
624 box
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
625 gtk_grid_attach (GTK_GRID (table
), box
, 0, row
, 2, 1);
627 scrollwin
= gtk_scrolled_window_new(NULL
,NULL
);
628 gtk_container_add(GTK_CONTAINER(box
), scrollwin
);
629 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin
), GTK_SHADOW_ETCHED_IN
);
630 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin
), GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
631 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrollwin
), HB_MINHEIGHT_LIST
);
632 gtk_widget_set_hexpand (scrollwin
, TRUE
);
633 gtk_widget_set_vexpand (scrollwin
, TRUE
);
634 treeview
= ui_tag_listview_new(FALSE
);
635 data
.LV_tag
= treeview
;
636 gtk_container_add(GTK_CONTAINER(scrollwin
), treeview
);
639 addreveal
= gtk_revealer_new ();
640 gtk_grid_attach (GTK_GRID (table
), addreveal
, 0, row
, 2, 1);
641 data
.ST_name
= gtk_entry_new ();
642 gtk_entry_set_placeholder_text(GTK_ENTRY(data
.ST_name
), _("new tag") );
643 gtk_widget_set_hexpand (data
.ST_name
, TRUE
);
644 gtk_container_add(GTK_CONTAINER(addreveal
), data
.ST_name
);
647 bbox
= gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL
);
648 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox
), GTK_BUTTONBOX_START
);
649 gtk_box_set_spacing (GTK_BOX (bbox
), SPACING_SMALL
);
650 gtk_grid_attach (GTK_GRID (table
), bbox
, 0, row
, 2, 1);
652 data
.BT_add
= gtk_toggle_button_new_with_mnemonic(_("_Add"));
653 gtk_container_add (GTK_CONTAINER (bbox
), data
.BT_add
);
656 data
.BT_edit
= gtk_button_new_with_mnemonic(_("_Edit"));
657 gtk_container_add (GTK_CONTAINER (bbox
), data
.BT_edit
);
659 data
.BT_delete
= gtk_button_new_with_mnemonic(_("_Delete"));
660 gtk_container_add (GTK_CONTAINER (bbox
), data
.BT_delete
);
663 //connect all our signals
664 g_object_bind_property (data
.BT_add
, "active", addreveal
, "reveal-child", G_BINDING_BIDIRECTIONAL
);
666 g_signal_connect (G_OBJECT (data
.ST_name
), "activate", G_CALLBACK (ui_tag_manage_dialog_add
), NULL
);
668 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
.LV_tag
)), "changed", G_CALLBACK (ui_tag_manage_dialog_selection
), NULL
);
669 g_signal_connect (GTK_TREE_VIEW(data
.LV_tag
), "row-activated", G_CALLBACK (ui_tag_manage_dialog_onRowActivated
), NULL
);
671 g_signal_connect (G_OBJECT (data
.BT_edit
), "clicked", G_CALLBACK (ui_tag_manage_dialog_edit
), NULL
);
672 g_signal_connect (G_OBJECT (data
.BT_delete
), "clicked", G_CALLBACK (ui_tag_manage_dialog_delete
), NULL
);
674 //setup, init and show dialog
676 ui_tag_listview_populate(data
.LV_tag
, 0);
677 ui_tag_manage_dialog_update(data
.LV_tag
, NULL
);
679 gtk_widget_show_all (dialog
);
682 gint result
= gtk_dialog_run (GTK_DIALOG (dialog
));
686 case GTK_RESPONSE_ACCEPT
:
687 //do_application_specific_something ();
690 //do_nothing_since_dialog_was_cancelled ();
694 // cleanup and destroy
696 gtk_widget_destroy (dialog
);
698 GLOBALS
->changes_count
+= data
.change
;