]> Dogcows Code - chaz/homebank/blob - src/ui-payee.c
Merge branch 'upstream'
[chaz/homebank] / src / ui-payee.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
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.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
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/>.
18 */
19
20
21 #include "homebank.h"
22
23 #include "ui-payee.h"
24 #include "ui-category.h"
25
26 #define MYDEBUG 0
27
28 #if MYDEBUG
29 #define DB(x) (x);
30 #else
31 #define DB(x);
32 #endif
33
34 /* our global datas */
35 extern struct HomeBank *GLOBALS;
36 extern struct Preferences *PREFS;
37
38
39 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
40
41
42 static GtkWidget *
43 container_get_nth(GtkBox *container, gint nth)
44 {
45 GList *lchild, *list;
46 GtkWidget *child;
47
48 if(!GTK_IS_CONTAINER(container))
49 return NULL;
50
51 lchild = list = gtk_container_get_children (GTK_CONTAINER(container));
52 child = g_list_nth_data (list, nth);
53 g_list_free(lchild);
54
55 return child;
56 }
57
58
59 GtkWidget *
60 ui_pay_entry_popover_get_entry(GtkBox *box)
61 {
62 return container_get_nth(box, 0);
63 }
64
65
66 Payee
67 *ui_pay_entry_popover_get(GtkBox *box)
68 {
69 GtkWidget *entry;
70 gchar *name;
71 Payee *item = NULL;
72
73 DB( g_print ("ui_pay_entry_popover_get()\n") );
74
75 entry = container_get_nth(box, 0);
76 if( entry != NULL && GTK_IS_ENTRY(entry) )
77 {
78 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (entry));
79 item = da_pay_get_by_name(name);
80 }
81 return item;
82 }
83
84
85 guint32
86 ui_pay_entry_popover_get_key_add_new(GtkBox *box)
87 {
88 Payee *item = ui_pay_entry_popover_get(box);
89 GtkWidget *entry;
90 GtkTreeModel *store;
91
92 if( item == NULL )
93 {
94 /* automatic add */
95 //todo: check prefs + ask the user here 1st time
96 entry = container_get_nth(box, 0);
97 if( entry != NULL && GTK_IS_ENTRY(entry) )
98 {
99 item = da_pay_malloc();
100 item->name = g_strdup(gtk_entry_get_text(GTK_ENTRY (entry)));
101 da_pay_append(item);
102
103 store = gtk_entry_completion_get_model(gtk_entry_get_completion(GTK_ENTRY(entry)));
104 if( store )
105 gtk_list_store_insert_with_values(GTK_LIST_STORE(store), NULL, -1,
106 0, item->name, -1);
107 }
108 }
109 return item->key;
110 }
111
112
113 guint32
114 ui_pay_entry_popover_get_key(GtkBox *box)
115 {
116 Payee *item = ui_pay_entry_popover_get(box);
117
118 return ((item != NULL) ? item->key : 0);
119 }
120
121
122 void
123 ui_pay_entry_popover_set_active(GtkBox *box, guint32 key)
124 {
125 GtkWidget *entry;
126
127 DB( g_print ("ui_pay_comboboxentry_set_active()\n") );
128
129 entry = container_get_nth(box, 0);
130 if( entry != NULL && GTK_IS_ENTRY(entry) )
131 {
132 Payee *item = da_pay_get(key);
133
134 ui_gtk_entry_set_text(GTK_WIDGET(entry), item != NULL ? item->name : "");
135 }
136 }
137
138
139 static void
140 ui_pay_entry_popover_cb_row_activated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
141 {
142 GtkTreeSelection *treeselection;
143 GtkTreeModel *model;
144 GtkTreeIter iter;
145 GtkEntry *entry = user_data;
146
147 if( GTK_IS_ENTRY(entry) )
148 {
149 treeselection = gtk_tree_view_get_selection(tree_view);
150 if( gtk_tree_selection_get_selected(treeselection, &model, &iter) )
151 {
152 gchar *item;
153
154 gtk_tree_model_get(model, &iter, 0, &item, -1);
155 gtk_entry_set_text(GTK_ENTRY(user_data), item);
156 g_free(item);
157 }
158 }
159 }
160
161
162 static void
163 ui_pay_entry_popover_populate(GtkListStore *store)
164 {
165 GHashTableIter hiter;
166 gpointer key, value;
167
168 g_hash_table_iter_init (&hiter, GLOBALS->h_pay);
169 while (g_hash_table_iter_next (&hiter, &key, &value))
170 {
171 Payee *pay = value;
172
173 gtk_list_store_insert_with_values(GTK_LIST_STORE(store), NULL, -1,
174 0, pay->name, -1);
175 }
176
177 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
178
179 }
180
181
182 static void
183 ui_pay_entry_popover_function (GtkEditable *editable, gpointer user_data)
184 {
185
186 g_print("text changed to %s\n", gtk_entry_get_text(GTK_ENTRY(editable)) );
187
188
189
190 }
191
192
193 static gint
194 ui_pay_entry_popover_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
195 {
196 gint retval = 0;
197 gchar *name1, *name2;
198
199 gtk_tree_model_get(model, a, 0, &name1, -1);
200 gtk_tree_model_get(model, b, 0, &name2, -1);
201
202 retval = hb_string_utf8_compare(name1, name2);
203
204 g_free(name2);
205 g_free(name1);
206
207 return retval;
208 }
209
210
211 static void
212 ui_pay_entry_popover_destroy( GtkWidget *widget, gpointer user_data )
213 {
214
215 g_print ("[pay entry popover] destroy\n");
216
217 }
218
219
220 GtkWidget *
221 ui_pay_entry_popover_new(GtkWidget *label)
222 {
223 GtkWidget *mainbox, *box, *entry, *menubutton, *image, *popover, *scrollwin, *treeview;
224 GtkListStore *store;
225 GtkEntryCompletion *completion;
226
227 g_print ("[pay entry popover] new\n");
228
229 mainbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
230 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(mainbox)), GTK_STYLE_CLASS_LINKED);
231
232 entry = gtk_entry_new();
233 gtk_box_pack_start(GTK_BOX(mainbox), entry, TRUE, TRUE, 0);
234
235 menubutton = gtk_menu_button_new ();
236 //data->MB_template = menubutton;
237 image = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
238 gtk_container_add(GTK_CONTAINER(menubutton), image);
239 //gtk_menu_button_set_direction (GTK_MENU_BUTTON(menubutton), GTK_ARROW_DOWN );
240 //gtk_widget_set_halign (menubutton, GTK_ALIGN_END);
241 gtk_box_pack_start(GTK_BOX(mainbox), menubutton, FALSE, FALSE, 0);
242
243 completion = gtk_entry_completion_new ();
244
245 gtk_entry_set_completion (GTK_ENTRY (entry), completion);
246 g_object_unref(completion);
247
248 store = gtk_list_store_new (1,
249 G_TYPE_STRING
250 );
251
252 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), ui_pay_entry_popover_compare_func, NULL, NULL);
253
254 ui_pay_entry_popover_populate(store);
255
256
257 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL(store));
258 g_object_unref(store);
259
260 gtk_entry_completion_set_text_column (completion, 0);
261
262 gtk_widget_show_all(mainbox);
263
264
265 box = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM);
266 scrollwin = gtk_scrolled_window_new(NULL,NULL);
267 gtk_box_pack_start(GTK_BOX(box), scrollwin, TRUE, TRUE, 0);
268 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN);
269 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
270 //gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrollwin), HB_MINHEIGHT_LIST);
271 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store));
272 gtk_container_add(GTK_CONTAINER(scrollwin), GTK_WIDGET(treeview));
273 gtk_widget_show_all(box);
274
275 //gtk_widget_set_can_focus(GTK_WIDGET(treeview), FALSE);
276
277 GtkCellRenderer *renderer;
278 GtkTreeViewColumn *column;
279
280 renderer = gtk_cell_renderer_text_new ();
281 column = gtk_tree_view_column_new_with_attributes (NULL,
282 renderer,
283 "text",
284 0,
285 NULL);
286 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
287
288
289 gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(treeview), TRUE);
290 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
291 gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(treeview), TRUE);
292
293
294 //gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_BROWSE);
295
296
297 popover = create_popover (menubutton, box, GTK_POS_BOTTOM);
298 gtk_widget_set_size_request (popover, HB_MINWIDTH_LIST, HB_MINHEIGHT_LIST);
299
300 gtk_menu_button_set_popover(GTK_MENU_BUTTON(menubutton), popover);
301
302 // connect our dispose function
303 g_signal_connect (entry, "destroy", G_CALLBACK (ui_pay_entry_popover_destroy), NULL);
304
305 g_signal_connect_after (entry , "changed", G_CALLBACK (ui_pay_entry_popover_function), NULL);
306
307 g_signal_connect (treeview, "row-activated", G_CALLBACK (ui_pay_entry_popover_cb_row_activated), entry);
308 g_signal_connect_swapped(treeview, "row-activated", G_CALLBACK(gtk_popover_popdown), popover);
309 //g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", G_CALLBACK (ui_pay_entry_popover_cb_selection), entry);
310 //g_signal_connect_swapped(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", G_CALLBACK(gtk_popover_popdown), popover);
311
312
313 if(label)
314 gtk_label_set_mnemonic_widget (GTK_LABEL(label), entry);
315
316 //gtk_widget_set_size_request(comboboxentry, HB_MINWIDTH_LIST, -1);
317
318 return mainbox;
319 }
320
321
322 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
323
324
325 /**
326 * ui_pay_comboboxentry_add:
327 *
328 * Add a single element (useful for dynamics add)
329 *
330 * Return value: --
331 *
332 */
333 static void
334 ui_pay_comboboxentry_add(GtkComboBox *entry_box, Payee *pay)
335 {
336 if( pay->name != NULL )
337 {
338 GtkTreeModel *model;
339 GtkTreeIter iter;
340
341 model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box));
342
343 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
344 gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, pay->name, -1);
345 }
346 }
347
348
349
350 /**
351 * ui_pay_comboboxentry_get_key_add_new:
352 *
353 * get the key of the active payee
354 * and create the payee if it do not exists
355 *
356 * Return value: the key or 0
357 *
358 */
359 guint32
360 ui_pay_comboboxentry_get_key_add_new(GtkComboBox *entry_box)
361 {
362 gchar *name;
363 Payee *item;
364
365 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
366 item = da_pay_get_by_name(name);
367 if( item == NULL )
368 {
369 /* automatic add */
370 //todo: check prefs + ask the user here 1st time
371 item = da_pay_malloc();
372 item->name = g_strdup(name);
373 da_pay_append(item);
374 ui_pay_comboboxentry_add(entry_box, item);
375 }
376
377 return item->key;
378 }
379
380 /**
381 * ui_pay_comboboxentry_get_key:
382 *
383 * get the key of the active payee
384 *
385 * Return value: the key or 0
386 *
387 */
388 guint32
389 ui_pay_comboboxentry_get_key(GtkComboBox *entry_box)
390 {
391 gchar *name;
392 Payee *item;
393
394 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
395 item = da_pay_get_by_name(name);
396
397 if( item != NULL )
398 return item->key;
399
400 return 0;
401 }
402
403
404 Payee
405 *ui_pay_comboboxentry_get(GtkComboBox *entry_box)
406 {
407 gchar *name;
408 Payee *item = NULL;
409
410 DB( g_print ("ui_pay_comboboxentry_get()\n") );
411
412 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
413 item = da_pay_get_by_name(name);
414
415 return item;
416 }
417
418
419 gboolean
420 ui_pay_comboboxentry_set_active(GtkComboBox *entry_box, guint32 key)
421 {
422 Payee *item;
423
424 DB( g_print ("ui_pay_comboboxentry_set_active()\n") );
425
426 DB( g_print("- key:%d\n", key) );
427
428 if( key > 0 )
429 {
430 item = da_pay_get(key);
431 if( item != NULL )
432 {
433 DB( g_print("- set combo to '%s'\n", item->name) );
434
435 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), item->name);
436 return TRUE;
437 }
438 }
439
440 DB( g_print("- set combo to ''\n") );
441
442 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), "");
443 return FALSE;
444 }
445
446
447 static void
448 ui_pay_comboboxentry_populate_ghfunc(gpointer key, gpointer value, struct payPopContext *ctx)
449 {
450 GtkTreeIter iter;
451 Payee *pay = value;
452
453 if( ( pay->key != ctx->except_key ) )
454 {
455 //gtk_list_store_append (GTK_LIST_STORE(ctx->model), &iter);
456 //gtk_list_store_set (GTK_LIST_STORE(ctx->model), &iter, 0, pay->name, -1);
457 gtk_list_store_insert_with_values(GTK_LIST_STORE(ctx->model), &iter, -1,
458 0, pay->name, -1);
459 }
460 }
461
462
463 //not used except here
464 static void
465 ui_pay_comboboxentry_populate_except(GtkComboBox *entry_box, GHashTable *hash, guint except_key)
466 {
467 GtkTreeModel *model;
468 //GtkEntryCompletion *completion;
469 struct payPopContext ctx;
470
471 DB( g_print ("ui_pay_comboboxentry_populate\n") );
472
473 model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box));
474 //completion = gtk_entry_get_completion(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
475
476 /* keep our model alive and detach from comboboxentry and completion */
477 //g_object_ref(model);
478 //gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), NULL);
479 //gtk_entry_completion_set_model (completion, NULL);
480
481 /* clear and populate */
482 ctx.model = model;
483 ctx.except_key = except_key;
484 gtk_list_store_clear (GTK_LIST_STORE(model));
485
486 //gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
487
488 g_hash_table_foreach(hash, (GHFunc)ui_pay_comboboxentry_populate_ghfunc, &ctx);
489
490 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
491
492 /* reatach our model */
493 //g_print("reattach\n");
494 //gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), model);
495 //gtk_entry_completion_set_model (completion, model);
496 //g_object_unref(model);
497
498 }
499
500 /**
501 * ui_pay_comboboxentry_populate:
502 *
503 * Populate the list and completion
504 *
505 * Return value: --
506 *
507 */
508 void
509 ui_pay_comboboxentry_populate(GtkComboBox *entry_box, GHashTable *hash)
510 {
511 ui_pay_comboboxentry_populate_except(entry_box, hash, -1);
512 }
513
514
515 static gint
516 ui_pay_comboboxentry_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
517 {
518 gint retval = 0;
519 gchar *name1, *name2;
520
521 gtk_tree_model_get(model, a, 0, &name1, -1);
522 gtk_tree_model_get(model, b, 0, &name2, -1);
523
524 retval = hb_string_utf8_compare(name1, name2);
525
526 g_free(name2);
527 g_free(name1);
528
529 return retval;
530 }
531
532
533 static void
534 ui_pay_comboboxentry_test (GtkCellLayout *cell_layout,
535 GtkCellRenderer *cell,
536 GtkTreeModel *tree_model,
537 GtkTreeIter *iter,
538 gpointer data)
539 {
540 gchar *name;
541
542 gtk_tree_model_get(tree_model, iter,
543 0, &name,
544 -1);
545
546 if( !name )
547 g_object_set(cell, "text", _("(no payee)"), NULL);
548 else
549 g_object_set(cell, "text", name, NULL);
550
551 //leak
552 g_free(name);
553
554 }
555
556 /**
557 * ui_pay_comboboxentry_new:
558 *
559 * Create a new payee comboboxentry
560 *
561 * Return value: the new widget
562 *
563 */
564 GtkWidget *
565 ui_pay_comboboxentry_new(GtkWidget *label)
566 {
567 GtkListStore *store;
568 GtkWidget *comboboxentry;
569 GtkEntryCompletion *completion;
570 GtkCellRenderer *renderer;
571
572 DB( g_print ("ui_pay_comboboxentry_new()\n") );
573
574 store = gtk_list_store_new (1,
575 G_TYPE_STRING
576 );
577 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), ui_pay_comboboxentry_compare_func, NULL, NULL);
578
579 completion = gtk_entry_completion_new ();
580 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL(store));
581 g_object_set(completion, "text-column", 0, NULL);
582
583 renderer = gtk_cell_renderer_text_new ();
584 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE);
585 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer, "text", 0, NULL);
586
587 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
588 renderer,
589 ui_pay_comboboxentry_test,
590 NULL, NULL);
591
592 // dothe same for combobox
593
594 comboboxentry = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(store));
595 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(comboboxentry), 0);
596
597 gtk_cell_layout_clear(GTK_CELL_LAYOUT (comboboxentry));
598
599 renderer = gtk_cell_renderer_text_new ();
600 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comboboxentry), renderer, TRUE);
601 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comboboxentry), renderer, "text", 0, NULL);
602
603 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (comboboxentry),
604 renderer,
605 ui_pay_comboboxentry_test,
606 NULL, NULL);
607
608 gtk_entry_set_completion (GTK_ENTRY (gtk_bin_get_child(GTK_BIN (comboboxentry))), completion);
609
610 g_object_unref(store);
611
612 if(label)
613 gtk_label_set_mnemonic_widget (GTK_LABEL(label), comboboxentry);
614
615 gtk_widget_set_size_request(comboboxentry, HB_MINWIDTH_LIST, -1);
616
617 return comboboxentry;
618 }
619
620
621 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
622
623 static void
624 ui_pay_listview_toggled_cb (GtkCellRendererToggle *cell,
625 gchar *path_str,
626 gpointer data)
627 {
628 GtkTreeModel *model = (GtkTreeModel *)data;
629 GtkTreeIter iter;
630 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
631 gboolean fixed;
632
633 /* get toggled iter */
634 gtk_tree_model_get_iter (model, &iter, path);
635 gtk_tree_model_get (model, &iter, LST_DEFPAY_TOGGLE, &fixed, -1);
636
637 /* do something with the value */
638 fixed ^= 1;
639
640 /* set new value */
641 gtk_list_store_set (GTK_LIST_STORE (model), &iter, LST_DEFPAY_TOGGLE, fixed, -1);
642
643 /* clean up */
644 gtk_tree_path_free (path);
645 }
646
647
648 static gint
649 ui_pay_listview_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
650 {
651 gint sortcol = GPOINTER_TO_INT(userdata);
652 Payee *entry1, *entry2;
653 gint retval = 0;
654
655 gtk_tree_model_get(model, a, LST_DEFPAY_DATAS, &entry1, -1);
656 gtk_tree_model_get(model, b, LST_DEFPAY_DATAS, &entry2, -1);
657
658 switch (sortcol)
659 {
660 case LST_DEFPAY_SORT_NAME:
661 retval = hb_string_utf8_compare(entry1->name, entry2->name);
662 break;
663 case LST_DEFPAY_SORT_USED:
664 retval = entry1->usage_count - entry2->usage_count;
665 break;
666 case LST_DEFPAY_SORT_DEFCAT:
667 {
668 Category *c1, *c2;
669
670 c1 = da_cat_get(entry1->kcat);
671 c2 = da_cat_get(entry2->kcat);
672 if( c1 != NULL && c2 != NULL )
673 {
674 retval = hb_string_utf8_compare(c1->fullname, c2->fullname);
675 }
676 }
677 break;
678 default:
679 g_return_val_if_reached(0);
680 }
681
682 return retval;
683 }
684
685
686 static void
687 ui_pay_listview_count_cell_data_function (GtkTreeViewColumn *col,
688 GtkCellRenderer *renderer,
689 GtkTreeModel *model,
690 GtkTreeIter *iter,
691 gpointer user_data)
692 {
693 Payee *entry;
694 gchar buffer[256];
695
696 gtk_tree_model_get(model, iter, LST_DEFPAY_DATAS, &entry, -1);
697 if(entry->usage_count > 0)
698 {
699 g_snprintf(buffer, 256-1, "%d", entry->usage_count);
700 g_object_set(renderer, "text", buffer, NULL);
701 }
702 else
703 g_object_set(renderer, "text", "", NULL);
704 }
705
706
707 static void
708 ui_pay_listview_defcat_cell_data_function (GtkTreeViewColumn *col,
709 GtkCellRenderer *renderer,
710 GtkTreeModel *model,
711 GtkTreeIter *iter,
712 gpointer user_data)
713 {
714 Payee *entry;
715 Category *cat;
716
717 gtk_tree_model_get(model, iter, LST_DEFPAY_DATAS, &entry, -1);
718
719 cat = da_cat_get(entry->kcat);
720 if( cat != NULL )
721 {
722 g_object_set(renderer, "text", cat->fullname, NULL);
723 }
724 else
725 g_object_set(renderer, "text", "", NULL);
726 }
727
728
729 static void
730 ui_pay_listview_name_cell_data_function (GtkTreeViewColumn *col,
731 GtkCellRenderer *renderer,
732 GtkTreeModel *model,
733 GtkTreeIter *iter,
734 gpointer user_data)
735 {
736 Payee *entry;
737 gchar *name;
738 #if MYDEBUG
739 gchar *string;
740 #endif
741
742 gtk_tree_model_get(model, iter, LST_DEFPAY_DATAS, &entry, -1);
743
744 if(entry->key == 0)
745 name = _("(no payee)");
746 else
747 name = entry->name;
748
749 #if MYDEBUG
750 string = g_strdup_printf ("%d > %s [ft=%d]", entry->key, name, entry->flt_select);
751 g_object_set(renderer, "text", string, NULL);
752 g_free(string);
753 #else
754 g_object_set(renderer, "text", name, NULL);
755 #endif
756
757 }
758
759
760 /* = = = = = = = = = = = = = = = = */
761
762
763 void
764 ui_pay_listview_add(GtkTreeView *treeview, Payee *item)
765 {
766 GtkTreeModel *model;
767 GtkTreeIter iter;
768
769 if( item->name != NULL )
770 {
771 model = gtk_tree_view_get_model(treeview);
772
773 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
774 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
775 LST_DEFPAY_TOGGLE, FALSE,
776 LST_DEFPAY_DATAS, item,
777 -1);
778 }
779 }
780
781 guint32
782 ui_pay_listview_get_selected_key(GtkTreeView *treeview)
783 {
784 GtkTreeSelection *selection;
785 GtkTreeModel *model;
786 GtkTreeIter iter;
787
788 selection = gtk_tree_view_get_selection(treeview);
789 if (gtk_tree_selection_get_selected(selection, &model, &iter))
790 {
791 Payee *item;
792
793 gtk_tree_model_get(model, &iter, LST_DEFPAY_DATAS, &item, -1);
794
795 if( item!= NULL )
796 return item->key;
797 }
798 return 0;
799 }
800
801 void
802 ui_pay_listview_remove_selected(GtkTreeView *treeview)
803 {
804 GtkTreeSelection *selection;
805 GtkTreeModel *model;
806 GtkTreeIter iter;
807
808 DB( g_print("ui_pay_listview_remove_selected() \n") );
809
810 selection = gtk_tree_view_get_selection(treeview);
811 if (gtk_tree_selection_get_selected(selection, &model, &iter))
812 {
813 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
814 }
815 }
816
817
818 struct PayListContext {
819 GtkTreeModel *model;
820 gchar *needle;
821 };
822
823
824 static void ui_pay_listview_populate_ghfunc(gpointer key, gpointer value, struct PayListContext *context)
825 {
826 GtkTreeIter iter;
827 Payee *item = value;
828 gboolean hastext = FALSE;
829 gboolean insert = TRUE;
830
831 //DB( g_print(" populate: %p\n", key) );
832 if( context->needle != NULL )
833 hastext = (strlen(context->needle) >= 2) ? TRUE : FALSE;
834
835 if(hastext)
836 {
837 insert = hb_string_utf8_strstr(item->name, context->needle, FALSE);
838 }
839
840 if( insert == TRUE)
841 {
842 gtk_list_store_insert_with_values(GTK_LIST_STORE(context->model), &iter, -1,
843 LST_DEFPAY_TOGGLE , FALSE,
844 LST_DEFPAY_DATAS, item,
845 -1);
846 }
847
848 }
849
850
851 void ui_pay_listview_populate(GtkWidget *treeview, gchar *needle)
852 {
853 struct PayListContext context;
854
855 DB( g_print("ui_pay_listview_populate \n") );
856
857 context.model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
858 context.needle = needle;
859
860 gtk_list_store_clear (GTK_LIST_STORE(context.model));
861
862 //g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
863 //gtk_tree_view_set_model(GTK_TREE_VIEW(view), NULL); /* Detach model from view */
864
865 /* populate */
866 g_hash_table_foreach(GLOBALS->h_pay, (GHFunc)ui_pay_listview_populate_ghfunc, &context);
867
868 //gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); /* Re-attach model to view */
869 //g_object_unref(model);
870 }
871
872
873 static gboolean ui_pay_listview_search_equal_func (GtkTreeModel *model,
874 gint column,
875 const gchar *key,
876 GtkTreeIter *iter,
877 gpointer search_data)
878 {
879 gboolean retval = TRUE;
880 gchar *normalized_string;
881 gchar *normalized_key;
882 gchar *case_normalized_string = NULL;
883 gchar *case_normalized_key = NULL;
884 Payee *item;
885
886 //gtk_tree_model_get_value (model, iter, column, &value);
887 gtk_tree_model_get(model, iter, LST_DEFPAY_DATAS, &item, -1);
888
889 if(item != NULL)
890 {
891 normalized_string = g_utf8_normalize (item->name, -1, G_NORMALIZE_ALL);
892 normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
893
894 if (normalized_string && normalized_key)
895 {
896 case_normalized_string = g_utf8_casefold (normalized_string, -1);
897 case_normalized_key = g_utf8_casefold (normalized_key, -1);
898
899 if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
900 retval = FALSE;
901 }
902
903 g_free (normalized_key);
904 g_free (normalized_string);
905 g_free (case_normalized_key);
906 g_free (case_normalized_string);
907 }
908 return retval;
909 }
910
911
912 GtkWidget *
913 ui_pay_listview_new(gboolean withtoggle, gboolean withcount)
914 {
915 GtkListStore *store;
916 GtkWidget *treeview;
917 GtkCellRenderer *renderer;
918 GtkTreeViewColumn *column;
919
920 DB( g_print("ui_pay_listview_new() \n") );
921
922 store = gtk_list_store_new(
923 NUM_LST_DEFPAY,
924 G_TYPE_BOOLEAN,
925 G_TYPE_POINTER
926 );
927
928 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
929 g_object_unref(store);
930
931 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (treeview), PREFS->grid_lines);
932
933 // column: toggle
934 if( withtoggle == TRUE )
935 {
936 renderer = gtk_cell_renderer_toggle_new ();
937 column = gtk_tree_view_column_new_with_attributes (_("Visible"),
938 renderer, "active", LST_DEFPAY_TOGGLE, NULL);
939 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
940
941 g_signal_connect (G_OBJECT(renderer), "toggled",
942 G_CALLBACK (ui_pay_listview_toggled_cb), store);
943
944 }
945
946 // column: name
947 renderer = gtk_cell_renderer_text_new ();
948
949 g_object_set(renderer,
950 "ellipsize", PANGO_ELLIPSIZE_END,
951 "ellipsize-set", TRUE,
952 //taken from nemo, not exactly a resize to content, but good compromise
953 "width-chars", 40,
954 NULL);
955
956 column = gtk_tree_view_column_new();
957 gtk_tree_view_column_set_title(column, _("Payee"));
958 gtk_tree_view_column_pack_start(column, renderer, TRUE);
959 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_pay_listview_name_cell_data_function, GINT_TO_POINTER(LST_DEFPAY_DATAS), NULL);
960 gtk_tree_view_column_set_alignment (column, 0.5);
961 gtk_tree_view_column_set_resizable(column, TRUE);
962 gtk_tree_view_column_set_min_width(column, HB_MINWIDTH_LIST);
963 gtk_tree_view_column_set_sort_column_id (column, LST_DEFPAY_SORT_NAME);
964 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
965
966 // column: usage
967 if( withcount == TRUE )
968 {
969 renderer = gtk_cell_renderer_text_new ();
970 g_object_set(renderer, "xalign", 0.5, NULL);
971
972 column = gtk_tree_view_column_new();
973 gtk_tree_view_column_set_title(column, _("Usage"));
974 gtk_tree_view_column_pack_start(column, renderer, TRUE);
975 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_pay_listview_count_cell_data_function, GINT_TO_POINTER(LST_DEFPAY_DATAS), NULL);
976 gtk_tree_view_column_set_alignment (column, 0.5);
977 gtk_tree_view_column_set_sort_column_id (column, LST_DEFPAY_SORT_USED);
978 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
979 }
980
981 // column: category
982 if( withtoggle == FALSE )
983 {
984 renderer = gtk_cell_renderer_text_new ();
985 g_object_set(renderer,
986 "ellipsize", PANGO_ELLIPSIZE_END,
987 "ellipsize-set", TRUE,
988 //taken from nemo, not exactly a resize to content, but good compromise
989 "width-chars", 40,
990 NULL);
991
992 column = gtk_tree_view_column_new();
993 gtk_tree_view_column_set_title(column, _("Category"));
994 gtk_tree_view_column_pack_start(column, renderer, TRUE);
995 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_pay_listview_defcat_cell_data_function, GINT_TO_POINTER(LST_DEFPAY_DATAS), NULL);
996 gtk_tree_view_column_set_alignment (column, 0.5);
997 gtk_tree_view_column_set_resizable(column, TRUE);
998 gtk_tree_view_column_set_sort_column_id (column, LST_DEFPAY_SORT_DEFCAT);
999 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
1000 }
1001
1002
1003 /* empty */
1004 column = gtk_tree_view_column_new();
1005 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
1006
1007
1008 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), ui_pay_listview_search_equal_func, NULL, NULL);
1009
1010 // treeview attribute
1011 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), withcount);
1012
1013 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFPAY_SORT_NAME, ui_pay_listview_compare_func, GINT_TO_POINTER(LST_DEFPAY_SORT_NAME), NULL);
1014 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFPAY_SORT_USED, ui_pay_listview_compare_func, GINT_TO_POINTER(LST_DEFPAY_SORT_USED), NULL);
1015 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFPAY_SORT_DEFCAT, ui_pay_listview_compare_func, GINT_TO_POINTER(LST_DEFPAY_SORT_DEFCAT), NULL);
1016
1017 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), LST_DEFPAY_SORT_NAME, GTK_SORT_ASCENDING);
1018
1019 return treeview;
1020 }
1021
1022
1023 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1024
1025 static void
1026 ui_pay_manage_dialog_delete_unused( GtkWidget *widget, gpointer user_data)
1027 {
1028 struct ui_pay_manage_dialog_data *data = user_data;
1029 gboolean result;
1030
1031 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
1032
1033 DB( g_print("(ui_pay_manage_dialog) delete unused - data %p\n", data) );
1034
1035 result = ui_dialog_msg_confirm_alert(
1036 GTK_WINDOW(data->window),
1037 _("Delete unused payee"),
1038 _("Are you sure you want to\npermanently delete unused payee?"),
1039 _("_Delete")
1040 );
1041
1042 if( result == GTK_RESPONSE_OK )
1043 {
1044 GtkTreeModel *model;
1045
1046 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_pay));
1047 gtk_list_store_clear (GTK_LIST_STORE(model));
1048
1049 payee_delete_unused();
1050
1051 ui_pay_listview_populate (data->LV_pay, NULL);
1052 }
1053 }
1054
1055
1056 /**
1057 * ui_pay_manage_dialog_load_csv:
1058 *
1059 */
1060 static void
1061 ui_pay_manage_dialog_load_csv( GtkWidget *widget, gpointer user_data)
1062 {
1063 struct ui_pay_manage_dialog_data *data = user_data;
1064 gchar *filename = NULL;
1065 gchar *error;
1066
1067 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
1068
1069 DB( g_print("(ui_pay_manage_dialog) load csv - data %p\n", data) );
1070
1071 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_OPEN, &filename, NULL) == TRUE )
1072 {
1073 DB( g_print(" + filename is %s\n", filename) );
1074
1075 if( !payee_load_csv(filename, &error) )
1076 {
1077 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
1078 _("File format error"),
1079 _("The CSV file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.")
1080 );
1081 }
1082
1083 g_free( filename );
1084 ui_pay_listview_populate(data->LV_pay, NULL);
1085 }
1086 }
1087
1088 /**
1089 * ui_pay_manage_dialog_save_csv:
1090 *
1091 */
1092 static void
1093 ui_pay_manage_dialog_save_csv( GtkWidget *widget, gpointer user_data)
1094 {
1095 struct ui_pay_manage_dialog_data *data = user_data;
1096 gchar *filename = NULL;
1097
1098 DB( g_print("(ui_pay_manage_dialog) save csv\n") );
1099
1100 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1101
1102 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, NULL) == TRUE )
1103 {
1104 DB( g_print(" + filename is %s\n", filename) );
1105
1106 payee_save_csv(filename);
1107 g_free( filename );
1108 }
1109 }
1110
1111
1112 /**
1113 * ui_pay_manage_dialog_add:
1114 *
1115 */
1116 static void
1117 ui_pay_manage_dialog_add(GtkWidget *widget, gpointer user_data)
1118 {
1119 struct ui_pay_manage_dialog_data *data;
1120 Payee *item;
1121 gchar *name;
1122
1123 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1124 DB( g_print("(defayee) add (data=%p)\n", data) );
1125
1126 name = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_name));
1127
1128 item = da_pay_malloc ();
1129 item->name = g_strdup(name);
1130
1131 g_strstrip(item->name);
1132
1133 if( strlen(item->name) > 0 )
1134 {
1135 if( da_pay_append(item) )
1136 {
1137 ui_pay_listview_add(GTK_TREE_VIEW(data->LV_pay), item);
1138 data->change++;
1139 }
1140 }
1141 else
1142 da_pay_free (item);
1143
1144 gtk_entry_set_text(GTK_ENTRY(data->ST_name), "");
1145 }
1146
1147
1148 static void ui_pay_manage_dialog_edit_entry_cb(GtkEditable *editable, gpointer user_data)
1149 {
1150 GtkDialog *window = user_data;
1151 const gchar *buffer;
1152
1153 buffer = gtk_entry_get_text(GTK_ENTRY(editable));
1154 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, strlen(buffer) > 0 ? TRUE : FALSE);
1155 }
1156
1157
1158 static void ui_pay_manage_dialog_edit(GtkWidget *dowidget, gpointer user_data)
1159 {
1160 struct ui_pay_manage_dialog_data *data;
1161 GtkWidget *dialog, *content_area, *content_grid, *group_grid;
1162 GtkWidget *label, *widget;
1163 GtkWidget *ST_name, *PO_cat, *NU_mode;
1164 gint crow, row;
1165 guint32 key;
1166
1167 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(dowidget, GTK_TYPE_WINDOW)), "inst_data");
1168 DB( g_print("(defayee) modify %p\n", data) );
1169
1170 key = ui_pay_listview_get_selected_key(GTK_TREE_VIEW(data->LV_pay));
1171 if( key > 0 )
1172 {
1173 Payee *item;
1174
1175 item = da_pay_get( key );
1176
1177 dialog = gtk_dialog_new_with_buttons (_("Edit..."),
1178 GTK_WINDOW (data->window),
1179 0,
1180 _("_Cancel"),
1181 GTK_RESPONSE_REJECT,
1182 _("_OK"),
1183 GTK_RESPONSE_ACCEPT,
1184 NULL);
1185
1186 content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
1187
1188 content_grid = gtk_grid_new();
1189 gtk_grid_set_row_spacing (GTK_GRID (content_grid), SPACING_LARGE);
1190 gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL);
1191 gtk_container_set_border_width (GTK_CONTAINER(content_grid), SPACING_MEDIUM);
1192 gtk_box_pack_start (GTK_BOX (content_area), content_grid, TRUE, TRUE, 0);
1193
1194 crow = 0;
1195 // group :: General
1196 group_grid = gtk_grid_new ();
1197 gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
1198 gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
1199 gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
1200
1201 //label = make_label_group(_("General"));
1202 //gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
1203
1204 row = 1;
1205 label = make_label_widget(_("_Name:"));
1206 gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
1207 widget = gtk_entry_new();
1208 ST_name = widget;
1209 gtk_widget_set_hexpand(widget, TRUE);
1210 gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
1211
1212 // group :: Default
1213 group_grid = gtk_grid_new ();
1214 gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
1215 gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
1216 gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
1217
1218 label = make_label_group(_("Default"));
1219 gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 4, 1);
1220
1221 row = 1;
1222 label = make_label_widget(_("_Category:"));
1223 gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
1224 widget = ui_cat_comboboxentry_new(label);
1225 PO_cat = widget;
1226 gtk_widget_set_hexpand (widget, TRUE);
1227 gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
1228
1229 row++;
1230 label = make_label_widget(_("Pa_yment:"));
1231 gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
1232 //5.2.4 we drop internal xfer here as it will disapear
1233 //widget = make_paymode_nointxfer(label);
1234 widget = make_paymode_nointxfer(label);
1235 NU_mode = widget;
1236 gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
1237
1238 //setup
1239 gtk_entry_set_text(GTK_ENTRY(ST_name), item->name);
1240 gtk_widget_grab_focus (ST_name);
1241 gtk_entry_set_activates_default (GTK_ENTRY(ST_name), TRUE);
1242
1243 ui_cat_comboboxentry_populate(GTK_COMBO_BOX(PO_cat), GLOBALS->h_cat);
1244 ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(PO_cat), item->kcat);
1245
1246 gtk_combo_box_set_active(GTK_COMBO_BOX(NU_mode), item->paymode);
1247
1248 g_signal_connect (G_OBJECT (ST_name), "changed", G_CALLBACK (ui_pay_manage_dialog_edit_entry_cb), dialog);
1249
1250 gtk_widget_show_all(content_grid);
1251
1252
1253 gtk_dialog_set_default_response(GTK_DIALOG( dialog ), GTK_RESPONSE_ACCEPT);
1254
1255 //wait for the user
1256 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1257
1258 if(result == GTK_RESPONSE_ACCEPT)
1259 {
1260 const gchar *name;
1261
1262 // 1: manage renaming
1263 name = gtk_entry_get_text(GTK_ENTRY(ST_name));
1264 // ignore if item is empty
1265 if (name && *name)
1266 {
1267 if( payee_rename(item, name) )
1268 {
1269 //to redraw the active entry
1270 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_pay));
1271 data->change++;
1272 }
1273 else
1274 {
1275 ui_dialog_msg_infoerror(GTK_WINDOW(dialog), GTK_MESSAGE_ERROR,
1276 _("Error"),
1277 _("Cannot rename this Payee,\n"
1278 "from '%s' to '%s',\n"
1279 "this name already exists."),
1280 item->name,
1281 name
1282 );
1283
1284 }
1285 }
1286
1287 item->kcat = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(PO_cat));
1288 item->paymode = gtk_combo_box_get_active(GTK_COMBO_BOX(NU_mode));
1289
1290 }
1291
1292 // cleanup and destroy
1293 gtk_widget_destroy (dialog);
1294 }
1295
1296 }
1297
1298
1299 static void ui_pay_manage_dialog_merge_entry_cb(GtkComboBox *widget, gpointer user_data)
1300 {
1301 GtkDialog *window = user_data;
1302 gchar *buffer;
1303
1304 buffer = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (widget))));
1305 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_OK, strlen(buffer) > 0 ? TRUE : FALSE);
1306 }
1307
1308
1309 static void ui_pay_manage_dialog_merge(GtkWidget *widget, gpointer user_data)
1310 {
1311 struct ui_pay_manage_dialog_data *data;
1312 GtkWidget *dialog, *content, *mainvbox;
1313 GtkWidget *getwidget, *togglebutton;
1314 GtkTreeSelection *selection;
1315 GtkTreeModel *model;
1316 GtkTreeIter iter;
1317
1318 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1319 DB( g_print("(defayee) merge %p\n", data) );
1320
1321 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_pay));
1322 //if true there is a selected node
1323 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1324 {
1325 Payee *srcpay;
1326 gchar *title;
1327 gchar *secondtext;
1328
1329 gtk_tree_model_get(model, &iter, LST_DEFPAY_DATAS, &srcpay, -1);
1330
1331 title = g_strdup_printf (
1332 _("Merge payee '%s'"), srcpay->name);
1333
1334 dialog = gtk_message_dialog_new (GTK_WINDOW (data->window),
1335 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1336 GTK_MESSAGE_WARNING,
1337 GTK_BUTTONS_NONE,
1338 title,
1339 NULL
1340 );
1341
1342 gtk_dialog_add_buttons (GTK_DIALOG(dialog),
1343 _("_Cancel"), GTK_RESPONSE_CANCEL,
1344 _("Merge"), GTK_RESPONSE_OK,
1345 NULL);
1346
1347 gtk_dialog_set_default_response(GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
1348
1349 content = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG (dialog));
1350 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
1351 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1352
1353 secondtext = _("Transactions assigned to this payee,\n"
1354 "will be moved to the payee selected below.");
1355
1356 g_object_set(GTK_MESSAGE_DIALOG (dialog), "secondary-text", secondtext, NULL);
1357 g_free(title);
1358
1359 getwidget = ui_pay_comboboxentry_new(NULL);
1360 gtk_box_pack_start (GTK_BOX (mainvbox), getwidget, FALSE, FALSE, 0);
1361
1362 secondtext = g_strdup_printf (
1363 _("_Delete the payee '%s'"), srcpay->name);
1364 togglebutton = gtk_check_button_new_with_mnemonic(secondtext);
1365 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton), TRUE);
1366 g_free(secondtext);
1367 gtk_box_pack_start (GTK_BOX (mainvbox), togglebutton, FALSE, FALSE, 0);
1368
1369 //setup
1370 //gtk_combo_box_set_active(GTK_COMBO_BOX(getwidget), oldpos);
1371 g_signal_connect (G_OBJECT (getwidget), "changed", G_CALLBACK (ui_pay_manage_dialog_merge_entry_cb), dialog);
1372 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE);
1373
1374 ui_pay_comboboxentry_populate_except(GTK_COMBO_BOX(getwidget), GLOBALS->h_pay, srcpay->key);
1375 gtk_widget_grab_focus (getwidget);
1376
1377 gtk_widget_show_all(mainvbox);
1378
1379 //wait for the user
1380 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1381
1382 if(result == GTK_RESPONSE_OK)
1383 {
1384 GtkTreeModel *model;
1385 Payee *newpay;
1386 guint dstpaykey;
1387
1388 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_pay));
1389 gtk_list_store_clear (GTK_LIST_STORE(model));
1390
1391 dstpaykey = ui_pay_comboboxentry_get_key_add_new(GTK_COMBO_BOX(getwidget));
1392
1393 payee_move(srcpay->key, dstpaykey);
1394
1395 newpay = da_pay_get(dstpaykey);
1396
1397 //#1771720: update count
1398 newpay->usage_count += srcpay->usage_count;
1399 srcpay->usage_count = 0;
1400
1401 // add the new payee to listview
1402 if(newpay)
1403 ui_pay_listview_add(GTK_TREE_VIEW(data->LV_pay), newpay);
1404
1405 // delete the old payee
1406 if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)) )
1407 {
1408 DB( g_print(" -> delete %d '%s'\n", srcpay->key, srcpay->name ) );
1409
1410 da_pay_remove(srcpay->key);
1411 ui_pay_listview_remove_selected(GTK_TREE_VIEW(data->LV_pay));
1412 }
1413
1414
1415 data->change++;
1416
1417 ui_pay_listview_populate(data->LV_pay, NULL);
1418 }
1419
1420 // cleanup and destroy
1421 gtk_widget_destroy (dialog);
1422 }
1423
1424 }
1425
1426
1427 /*
1428 ** delete the selected payee to our treeview and temp GList
1429 */
1430 static void ui_pay_manage_dialog_delete(GtkWidget *widget, gpointer user_data)
1431 {
1432 struct ui_pay_manage_dialog_data *data;
1433 Payee *item;
1434 guint32 key;
1435 gint result;
1436
1437
1438 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1439 DB( g_print("(ui_pay_manage_dialog) delete (data=%p)\n", data) );
1440
1441 key = ui_pay_listview_get_selected_key(GTK_TREE_VIEW(data->LV_pay));
1442 if( key > 0 )
1443 {
1444 gchar *title;
1445 gchar *secondtext = NULL;
1446
1447 item = da_pay_get(key);
1448
1449 title = g_strdup_printf (
1450 _("Are you sure you want to permanently delete '%s'?"), item->name);
1451
1452 if( item->usage_count > 0 )
1453 {
1454 secondtext = _("This payee is used.\n"
1455 "Any transaction using that payee will be set to (no payee)");
1456 }
1457
1458 result = ui_dialog_msg_confirm_alert(
1459 GTK_WINDOW(data->window),
1460 title,
1461 secondtext,
1462 _("_Delete")
1463 );
1464
1465 g_free(title);
1466
1467 if( result == GTK_RESPONSE_OK )
1468 {
1469 payee_move(key, 0);
1470 ui_pay_listview_remove_selected(GTK_TREE_VIEW(data->LV_pay));
1471 da_pay_remove(key);
1472 data->change++;
1473 }
1474
1475 }
1476 }
1477
1478
1479 static void ui_pay_manage_dialog_update(GtkWidget *treeview, gpointer user_data)
1480 {
1481 struct ui_pay_manage_dialog_data *data;
1482 gboolean sensitive;
1483 guint32 key;
1484
1485 DB( g_print("\n(ui_pay_manage_dialog) cursor changed\n") );
1486
1487 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
1488
1489 key = ui_pay_listview_get_selected_key(GTK_TREE_VIEW(data->LV_pay));
1490
1491 sensitive = (key > 0) ? TRUE : FALSE;
1492 gtk_widget_set_sensitive(data->BT_edit, sensitive);
1493 gtk_widget_set_sensitive(data->BT_merge, sensitive);
1494 gtk_widget_set_sensitive(data->BT_delete, sensitive);
1495
1496 }
1497
1498
1499 /*
1500 **
1501 */
1502 static void ui_pay_manage_dialog_selection(GtkTreeSelection *treeselection, gpointer user_data)
1503 {
1504 ui_pay_manage_dialog_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), NULL);
1505 }
1506
1507 static void ui_pay_manage_dialog_onRowActivated (GtkTreeView *treeview,
1508 GtkTreePath *path,
1509 GtkTreeViewColumn *col,
1510 gpointer user_data)
1511 {
1512 GtkTreeModel *model;
1513 GtkTreeIter iter;
1514
1515 DB( g_print("ui_pay_manage_dialog_onRowActivated()\n") );
1516
1517
1518 model = gtk_tree_view_get_model(treeview);
1519 gtk_tree_model_get_iter_first(model, &iter);
1520 if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), &iter) == FALSE)
1521 {
1522 ui_pay_manage_dialog_edit(GTK_WIDGET(treeview), NULL);
1523 }
1524 }
1525
1526
1527 static void
1528 ui_pay_manage_search_changed_cb (GtkWidget *widget, gpointer user_data)
1529 {
1530 struct ui_pay_manage_dialog_data *data = user_data;
1531 gchar *needle;
1532
1533 DB( g_printf("\n[ui_pay_manage_dialog] search_changed_cb\n") );
1534
1535 needle = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_search));
1536 ui_pay_listview_populate(data->LV_pay, needle);
1537 }
1538
1539
1540 GtkWidget *ui_pay_manage_dialog (void)
1541 {
1542 struct ui_pay_manage_dialog_data data;
1543 GtkWidget *dialog, *content, *mainvbox, *box, *bbox, *treeview, *scrollwin, *table;
1544 GtkWidget *menu, *menuitem, *widget, *image, *searchbar, *addreveal;
1545 gint w, h, row;
1546
1547 dialog = gtk_dialog_new_with_buttons (_("Manage Payees"),
1548 GTK_WINDOW(GLOBALS->mainwindow),
1549 0,
1550 _("_Close"), GTK_RESPONSE_ACCEPT,
1551 NULL);
1552
1553 /*dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", TRUE, NULL);
1554 gtk_window_set_title (GTK_WINDOW (dialog), _("Manage Payees"));
1555 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW(GLOBALS->mainwindow));
1556 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1557 */
1558 //gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
1559
1560 data.window = dialog;
1561 data.change = 0;
1562
1563 gtk_window_set_icon_name(GTK_WINDOW (dialog), ICONNAME_HB_PAYEE);
1564
1565 //set a nice dialog size
1566 gtk_window_get_size(GTK_WINDOW(GLOBALS->mainwindow), &w, &h);
1567 gtk_window_set_default_size (GTK_WINDOW(dialog), -1, h/PHI);
1568
1569
1570 //store our dialog private data
1571 g_object_set_data(G_OBJECT(dialog), "inst_data", (gpointer)&data);
1572 DB( g_print("(ui_pay_manage_dialog) dialog=%p, inst_data=%p\n", dialog, &data) );
1573
1574 g_signal_connect (dialog, "destroy",
1575 G_CALLBACK (gtk_widget_destroyed), &dialog);
1576
1577 //dialog contents
1578 content = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
1579 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
1580 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1581 gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM);
1582
1583 //our table
1584 table = gtk_grid_new ();
1585 gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL);
1586 gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM);
1587 gtk_box_pack_start (GTK_BOX (mainvbox), table, TRUE, TRUE, 0);
1588
1589 row = 0;
1590 bbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_MEDIUM);
1591 gtk_grid_attach (GTK_GRID (table), bbox, 0, row, 2, 1);
1592 //test headerbar
1593 //content = gtk_dialog_get_header_bar(GTK_DIALOG (dialog));
1594
1595 menu = gtk_menu_new ();
1596 gtk_widget_set_halign (menu, GTK_ALIGN_END);
1597
1598 menuitem = gtk_menu_item_new_with_mnemonic (_("_Import CSV"));
1599 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1600 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_pay_manage_dialog_load_csv), &data);
1601
1602 menuitem = gtk_menu_item_new_with_mnemonic (_("E_xport CSV"));
1603 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1604 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_pay_manage_dialog_save_csv), &data);
1605
1606 menuitem = gtk_separator_menu_item_new();
1607 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1608
1609 menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete unused"));
1610 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1611 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_pay_manage_dialog_delete_unused), &data);
1612
1613 gtk_widget_show_all (menu);
1614
1615
1616 widget = gtk_menu_button_new();
1617 image = gtk_image_new_from_icon_name (ICONNAME_HB_BUTTON_MENU, GTK_ICON_SIZE_MENU);
1618 g_object_set (widget, "image", image, "popup", GTK_MENU(menu), NULL);
1619 gtk_widget_set_halign (widget, GTK_ALIGN_END);
1620 gtk_box_pack_end(GTK_BOX (bbox), widget, FALSE, FALSE, 0);
1621 //gtk_header_bar_pack_end(GTK_HEADER_BAR (content), widget);
1622
1623 data.BT_search = gtk_toggle_button_new ();
1624 image = gtk_image_new_from_icon_name (ICONNAME_SYSTEM_SEARCH, GTK_ICON_SIZE_BUTTON);
1625 gtk_button_set_image (GTK_BUTTON(data.BT_search), image);
1626 gtk_box_pack_end(GTK_BOX (bbox), data.BT_search, FALSE, FALSE, 0);
1627 //gtk_header_bar_pack_end(GTK_HEADER_BAR (content), data.BT_search);
1628
1629 //search + list
1630 row++;
1631 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1632 gtk_grid_attach (GTK_GRID (table), box, 0, row, 2, 1);
1633
1634 searchbar = gtk_search_bar_new();
1635 gtk_container_add(GTK_CONTAINER(box), searchbar);
1636 widget = make_search();
1637 data.ST_search = widget;
1638 gtk_container_add (GTK_CONTAINER (searchbar), widget);
1639 gtk_search_bar_connect_entry(GTK_SEARCH_BAR(searchbar), GTK_ENTRY(data.ST_search));
1640 gtk_search_bar_set_show_close_button(GTK_SEARCH_BAR(searchbar), TRUE);
1641
1642 scrollwin = gtk_scrolled_window_new(NULL,NULL);
1643 gtk_container_add(GTK_CONTAINER(box), scrollwin);
1644 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN);
1645 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1646 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrollwin), HB_MINHEIGHT_LIST);
1647 gtk_widget_set_hexpand (scrollwin, TRUE);
1648 gtk_widget_set_vexpand (scrollwin, TRUE);
1649 treeview = ui_pay_listview_new(FALSE, TRUE);
1650 data.LV_pay = treeview;
1651 gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
1652
1653 row++;
1654 addreveal = gtk_revealer_new ();
1655 gtk_grid_attach (GTK_GRID (table), addreveal, 0, row, 2, 1);
1656 data.ST_name = gtk_entry_new ();
1657 gtk_entry_set_placeholder_text(GTK_ENTRY(data.ST_name), _("new payee") );
1658 gtk_widget_set_hexpand (data.ST_name, TRUE);
1659 gtk_container_add(GTK_CONTAINER(addreveal), data.ST_name);
1660
1661 row++;
1662 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1663 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START);
1664 gtk_box_set_spacing (GTK_BOX (bbox), SPACING_SMALL);
1665 gtk_grid_attach (GTK_GRID (table), bbox, 0, row, 2, 1);
1666
1667 data.BT_add = gtk_toggle_button_new_with_mnemonic(_("_Add"));
1668 gtk_container_add (GTK_CONTAINER (bbox), data.BT_add);
1669
1670 //todo: useless ?
1671 data.BT_edit = gtk_button_new_with_mnemonic(_("_Edit"));
1672 gtk_container_add (GTK_CONTAINER (bbox), data.BT_edit);
1673
1674 data.BT_merge = gtk_button_new_with_mnemonic(_("_Merge"));
1675 gtk_container_add (GTK_CONTAINER (bbox), data.BT_merge);
1676
1677 data.BT_delete = gtk_button_new_with_mnemonic(_("_Delete"));
1678 gtk_container_add (GTK_CONTAINER (bbox), data.BT_delete);
1679
1680
1681 //connect all our signals
1682 g_object_bind_property (data.BT_add, "active", addreveal, "reveal-child", G_BINDING_BIDIRECTIONAL);
1683 g_object_bind_property (data.BT_search, "active", searchbar, "search-mode-enabled", G_BINDING_BIDIRECTIONAL);
1684
1685 g_signal_connect (G_OBJECT (data.ST_search), "search-changed", G_CALLBACK (ui_pay_manage_search_changed_cb), &data);
1686 g_signal_connect (G_OBJECT (data.ST_name), "activate", G_CALLBACK (ui_pay_manage_dialog_add), NULL);
1687
1688 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_pay)), "changed", G_CALLBACK (ui_pay_manage_dialog_selection), NULL);
1689 g_signal_connect (GTK_TREE_VIEW(data.LV_pay), "row-activated", G_CALLBACK (ui_pay_manage_dialog_onRowActivated), NULL);
1690
1691 g_signal_connect (G_OBJECT (data.BT_edit), "clicked", G_CALLBACK (ui_pay_manage_dialog_edit), NULL);
1692 g_signal_connect (G_OBJECT (data.BT_merge), "clicked", G_CALLBACK (ui_pay_manage_dialog_merge), NULL);
1693 g_signal_connect (G_OBJECT (data.BT_delete), "clicked", G_CALLBACK (ui_pay_manage_dialog_delete), NULL);
1694
1695 //setup, init and show dialog
1696 payee_fill_usage();
1697 ui_pay_listview_populate(data.LV_pay, NULL);
1698 ui_pay_manage_dialog_update(data.LV_pay, NULL);
1699
1700 gtk_widget_show_all (dialog);
1701
1702 //wait for the user
1703 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1704
1705 switch (result)
1706 {
1707 case GTK_RESPONSE_ACCEPT:
1708 //do_application_specific_something ();
1709 break;
1710 default:
1711 //do_nothing_since_dialog_was_cancelled ();
1712 break;
1713 }
1714
1715 // cleanup and destroy
1716
1717 gtk_widget_destroy (dialog);
1718
1719 GLOBALS->changes_count += data.change;
1720
1721 return NULL;
1722 }
1723
This page took 0.112515 seconds and 4 git commands to generate.