]> Dogcows Code - chaz/homebank/blob - src/ui-category.c
import homebank-5.1.3
[chaz/homebank] / src / ui-category.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2017 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-category.h"
24
25 #define MYDEBUG 0
26
27 #if MYDEBUG
28 #define DB(x) (x);
29 #else
30 #define DB(x);
31 #endif
32
33 /* our global datas */
34 extern struct HomeBank *GLOBALS;
35 extern struct Preferences *PREFS;
36
37
38 gchar *CYA_CAT_TYPE[] = {
39 N_("Expense"),
40 N_("Income"),
41 NULL
42 };
43
44 static void ui_cat_manage_populate_listview(struct ui_cat_manage_dialog_data *data);
45
46 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
47
48 /**
49 * ui_cat_comboboxentry_get_name:
50 *
51 * get the name of the active category or -1
52 *
53 * Return value: a new allocated name tobe freed with g_free
54 *
55 */
56 gchar *
57 ui_cat_comboboxentry_get_name(GtkComboBox *entry_box)
58 {
59 gchar *cbname;
60 gchar *name = NULL;
61
62 DB( g_print ("ui_cat_comboboxentry_get_name()\n") );
63
64 cbname = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
65 if( cbname != NULL)
66 {
67 name = g_strdup(cbname);
68 g_strstrip(name);
69 }
70
71 return name;
72 }
73
74
75 /**
76 * ui_cat_comboboxentry_get_key:
77 *
78 * get the key of the active category or -1
79 *
80 * Return value: the key or -1
81 *
82 */
83 guint32
84 ui_cat_comboboxentry_get_key_add_new(GtkComboBox *entry_box)
85 {
86 Category *item;
87 gchar *name;
88
89 DB( g_print ("ui_cat_comboboxentry_get_key()\n") );
90
91 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
92
93 if( name == NULL)
94 return -1;
95
96 item = da_cat_get_by_fullname(name);
97 if(item == NULL)
98 {
99 /* automatic add */
100 //todo: check prefs + ask the user here 1st time
101 item = da_cat_append_ifnew_by_fullname(name, FALSE);
102
103 ui_cat_comboboxentry_add(entry_box, item);
104 }
105
106 return item->key;
107 }
108
109
110 /**
111 * ui_cat_comboboxentry_get_key:
112 *
113 * get the key of the active category or -1
114 *
115 * Return value: the key or -1
116 *
117 */
118 guint32
119 ui_cat_comboboxentry_get_key(GtkComboBox *entry_box)
120 {
121 Category *item;
122 gchar *name;
123
124 DB( g_print ("ui_cat_comboboxentry_get_key()\n") );
125
126 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
127 if( name == NULL)
128 return -1;
129
130 item = da_cat_get_by_fullname(name);
131 if(item != NULL)
132 return item->key;
133
134 return -1;
135 }
136
137
138 Category
139 *ui_cat_comboboxentry_get(GtkComboBox *entry_box)
140 {
141 Category *item = NULL;
142 gchar *name;
143
144 DB( g_print ("ui_cat_comboboxentry_get_key()\n") );
145
146 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
147 if(name == NULL)
148 return NULL;
149
150 item = da_cat_get_by_fullname(name);
151
152 return item;
153 }
154
155
156 gboolean
157 ui_cat_comboboxentry_set_active(GtkComboBox *entry_box, guint32 key)
158 {
159 Category *item;
160 gchar *fullname;
161
162 DB( g_print ("ui_cat_comboboxentry_set_active()\n") );
163
164
165 if( key > 0 )
166 {
167 item = da_cat_get(key);
168 if( item != NULL)
169 {
170 if( item->parent == 0)
171 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), item->name);
172 else
173 {
174 fullname = da_cat_get_fullname(item);
175 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), fullname);
176 g_free(fullname);
177 }
178 return TRUE;
179 }
180 }
181 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), "");
182 return FALSE;
183 }
184
185 /**
186 * ui_cat_comboboxentry_add:
187 *
188 * Add a single element (useful for dynamics add)
189 *
190 * Return value: --
191 *
192 */
193 void
194 ui_cat_comboboxentry_add(GtkComboBox *entry_box, Category *item)
195 {
196
197 DB( g_print ("ui_cat_comboboxentry_add()\n") );
198
199
200 DB( g_print (" -> try to add: '%s'\n", item->name) );
201
202 if( item->name != NULL )
203 {
204 GtkTreeModel *model;
205 GtkTreeIter iter;
206
207 gchar *fullname, *name;
208
209 fullname = da_cat_get_fullname(item);
210 model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box));
211
212 if( item->parent == 0 )
213 name = g_strdup(item->name);
214 else
215 name = g_strdup_printf(" - %s", item->name);
216
217 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
218 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
219 LST_CMBCAT_DATAS, item,
220 LST_CMBCAT_FULLNAME, fullname,
221 LST_CMBCAT_SORTNAME, NULL,
222 LST_CMBCAT_NAME, name,
223 LST_CMBCAT_SUBCAT, item->parent == 0 ? 1 : 0,
224 -1);
225
226 g_free(fullname);
227 g_free(name);
228
229 }
230 }
231
232
233 static void
234 ui_cat_comboboxentry_populate_ghfunc(gpointer key, gpointer value, struct catPopContext *ctx)
235 {
236 GtkTreeIter iter;
237 Category *item = value;
238 Category *pitem = NULL;
239 gchar *fullname, *name, *sortname;
240 gchar type;
241
242 if( ( item->key != ctx->except_key ) )
243 {
244 pitem = da_cat_get(item->parent);
245
246 type = (item->flags & GF_INCOME) ? '+' : '-';
247 fullname = da_cat_get_fullname(item);
248 sortname = NULL;
249 name = NULL;
250
251 //DB( g_print ("cat combo populate [%d:%d] %s\n", item->parent, item->key, fullname) );
252
253 if(item->key == 0)
254 {
255 name = g_strdup(item->name);
256 sortname = g_strdup(item->name);
257 }
258 else
259 {
260 if( item->parent == 0 )
261 {
262 name = g_strdup_printf("%s [%c]", item->name, type);
263 sortname = g_strdup_printf("%s", item->name);
264 }
265 else
266 {
267 if(pitem)
268 {
269 name = g_strdup_printf(" %c %s", type, item->name);
270 sortname = g_strdup_printf("%s_%s", pitem->name, item->name);
271 }
272 }
273 }
274
275 hb_string_replace_char(' ', sortname);
276
277 //gtk_list_store_append (GTK_LIST_STORE(ctx->model), &iter);
278 //gtk_list_store_set (GTK_LIST_STORE(ctx->model), &iter,
279 gtk_list_store_insert_with_values(GTK_LIST_STORE(ctx->model), &iter, -1,
280 LST_CMBCAT_DATAS, item,
281 LST_CMBCAT_FULLNAME, fullname,
282 LST_CMBCAT_SORTNAME, sortname,
283 LST_CMBCAT_NAME, name,
284 LST_CMBCAT_SUBCAT, item->parent == 0 ? 1 : 0,
285 -1);
286
287 DB( g_print(" - add [%2d:%2d] '%-12s' '%-12s' '%s' '%s' %d\n", item->parent, item->key, pitem->name, name, fullname, sortname, item->parent == 0 ? 1 : 0) );
288
289 g_free(sortname);
290 g_free(fullname);
291 g_free(name);
292 }
293
294 }
295
296 /**
297 * ui_cat_comboboxentry_populate:
298 *
299 * Populate the list and completion
300 *
301 * Return value: --
302 *
303 */
304 void
305 ui_cat_comboboxentry_populate(GtkComboBox *entry_box, GHashTable *hash)
306 {
307 ui_cat_comboboxentry_populate_except(entry_box, hash, -1);
308 }
309
310 void
311 ui_cat_comboboxentry_populate_except(GtkComboBox *entry_box, GHashTable *hash, guint except_key)
312 {
313 GtkTreeModel *model;
314 //GtkEntryCompletion *completion;
315 struct catPopContext ctx;
316
317 DB( g_print ("ui_cat_comboboxentry_populate()\n") );
318
319 model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box));
320 //completion = gtk_entry_get_completion(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
321
322 /* keep our model alive and detach from comboboxentry and completion */
323 //g_object_ref(model);
324 //gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), NULL);
325 //gtk_entry_completion_set_model (completion, NULL);
326
327 /* clear and populate */
328
329 ctx.model = model;
330 ctx.except_key = except_key;
331 gtk_list_store_clear (GTK_LIST_STORE(model));
332
333 //gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
334
335 g_hash_table_foreach(hash, (GHFunc)ui_cat_comboboxentry_populate_ghfunc, &ctx);
336
337 /* reatach our model */
338 //gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), model);
339 //gtk_entry_completion_set_model (completion, model);
340 //g_object_unref(model);
341
342 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
343
344 }
345
346
347
348 static gint
349 ui_cat_comboboxentry_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
350 {
351 gint retval = 0;
352 gchar *name1, *name2;
353
354 gtk_tree_model_get(model, a,
355 LST_CMBCAT_SORTNAME, &name1,
356 -1);
357 gtk_tree_model_get(model, b,
358 LST_CMBCAT_SORTNAME, &name2,
359 -1);
360
361 //DB( g_print(" compare '%s' '%s'\n", name1, name2) );
362
363 retval = hb_string_utf8_compare(name1, name2);
364
365 g_free(name2);
366 g_free(name1);
367
368 return retval;
369 }
370
371
372 static void
373 ui_cat_comboboxentry_test (GtkCellLayout *cell_layout,
374 GtkCellRenderer *cell,
375 GtkTreeModel *tree_model,
376 GtkTreeIter *iter,
377 gpointer data)
378 {
379 gchar *name;
380 gboolean subcat;
381 gint style;
382
383 //PANGO_STYLE_ITALIC
384
385 gtk_tree_model_get(tree_model, iter,
386 LST_CMBCAT_NAME, &name,
387 LST_CMBCAT_SUBCAT, &subcat,
388 -1);
389
390 style = subcat == 0 ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
391
392 if( name == NULL )
393 name = _("(no category)"); //todo: not used
394
395 g_object_set(cell,
396 "style", style,
397 "text", name,
398 NULL);
399 }
400
401
402
403 static gboolean
404 ui_cat_comboboxentry_completion_func (GtkEntryCompletion *completion,
405 const gchar *key,
406 GtkTreeIter *iter,
407 gpointer user_data)
408 {
409 gchar *item = NULL;
410 gchar *normalized_string;
411 gchar *case_normalized_string;
412
413 gboolean ret = FALSE;
414
415 GtkTreeModel *model;
416
417 model = gtk_entry_completion_get_model (completion);
418
419 gtk_tree_model_get (model, iter,
420 LST_CMBCAT_FULLNAME, &item,
421 -1);
422
423 if (item != NULL)
424 {
425 normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
426
427 if (normalized_string != NULL)
428 {
429 case_normalized_string = g_utf8_casefold (normalized_string, -1);
430
431 //g_print("match '%s' for '%s' ?\n", key, case_normalized_string);
432 //if (!strncmp (key, case_normalized_string, strlen (key)))
433 if (g_strstr_len (case_normalized_string, strlen (case_normalized_string), key ))
434 {
435 ret = TRUE;
436 // g_print(" ==> yes !\n");
437
438 }
439
440 g_free (case_normalized_string);
441 }
442 g_free (normalized_string);
443 }
444 g_free (item);
445
446 return ret;
447 }
448
449
450 /**
451 * ui_cat_comboboxentry_new:
452 *
453 * Create a new category comboboxentry
454 *
455 * Return value: the new widget
456 *
457 */
458 GtkWidget *
459 ui_cat_comboboxentry_new(GtkWidget *label)
460 {
461 GtkListStore *store;
462 GtkWidget *comboboxentry;
463 GtkEntryCompletion *completion;
464 GtkCellRenderer *renderer;
465
466 DB( g_print ("ui_cat_comboboxentry_new()\n") );
467
468 store = gtk_list_store_new (NUM_LST_CMBCAT,
469 G_TYPE_POINTER,
470 G_TYPE_STRING, //fullname Car:Fuel
471 G_TYPE_STRING, //parent name Car
472 G_TYPE_STRING, //name Car or Fuel
473 G_TYPE_BOOLEAN //subcat = 1
474 );
475 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), ui_cat_comboboxentry_compare_func, NULL, NULL);
476
477 completion = gtk_entry_completion_new ();
478 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL(store));
479 //g_object_set(completion, "text-column", LST_CMBCAT_FULLNAME, NULL);
480 gtk_entry_completion_set_match_func(completion, ui_cat_comboboxentry_completion_func, NULL, NULL);
481 //gtk_entry_completion_set_minimum_key_length(completion, 2);
482
483 gtk_entry_completion_set_text_column(completion, 1);
484
485 /*renderer = gtk_cell_renderer_text_new ();
486 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE);
487 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer, "text", LST_CMBCAT_FULLNAME, NULL);
488
489 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
490 renderer,
491 ui_cat_comboboxentry_test,
492 NULL, NULL);
493 */
494
495 // dothe same for combobox
496
497 comboboxentry = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(store));
498 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(comboboxentry), LST_CMBCAT_FULLNAME);
499
500 gtk_cell_layout_clear(GTK_CELL_LAYOUT (comboboxentry));
501
502 renderer = gtk_cell_renderer_text_new ();
503 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comboboxentry), renderer, TRUE);
504 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comboboxentry), renderer, "text", LST_CMBCAT_FULLNAME, NULL);
505
506 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (comboboxentry),
507 renderer,
508 ui_cat_comboboxentry_test,
509 NULL, NULL);
510
511 gtk_entry_set_completion (GTK_ENTRY (gtk_bin_get_child(GTK_BIN (comboboxentry))), completion);
512
513 g_object_unref(store);
514
515 if(label)
516 gtk_label_set_mnemonic_widget (GTK_LABEL(label), comboboxentry);
517
518 gtk_widget_set_size_request(comboboxentry, HB_MINWIDTH_LIST, -1);
519
520 return comboboxentry;
521 }
522
523 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
524
525 static void
526 ui_cat_listview_fixed_toggled (GtkCellRendererToggle *cell,
527 gchar *path_str,
528 gpointer data)
529 {
530 GtkTreeModel *model = (GtkTreeModel *)data;
531 GtkTreeIter iter;
532 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
533 gboolean fixed;
534
535 /* get toggled iter */
536 gtk_tree_model_get_iter (model, &iter, path);
537 gtk_tree_model_get (model, &iter, LST_DEFCAT_TOGGLE, &fixed, -1);
538
539 /* do something with the value */
540 fixed ^= 1;
541
542 /* set new value */
543 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, LST_DEFCAT_TOGGLE, fixed, -1);
544
545 /* clean up */
546 gtk_tree_path_free (path);
547 }
548
549 static gint
550 ui_cat_listview_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
551 {
552 gint sortcol = GPOINTER_TO_INT(userdata);
553 Category *entry1, *entry2;
554 gint retval = 0;
555
556 gtk_tree_model_get(model, a, LST_DEFCAT_DATAS, &entry1, -1);
557 gtk_tree_model_get(model, b, LST_DEFCAT_DATAS, &entry2, -1);
558
559 switch (sortcol)
560 {
561 case LST_DEFCAT_SORT_NAME:
562 retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME);
563 if(!retval)
564 {
565 retval = hb_string_utf8_compare(entry1->name, entry2->name);
566 }
567 break;
568 case LST_DEFCAT_SORT_USED:
569 retval = entry1->usage_count - entry2->usage_count;
570 break;
571 default:
572 g_return_val_if_reached(0);
573 }
574 return retval;
575 }
576
577
578 /*
579 ** draw some text from the stored data structure
580 */
581 static void
582 ui_cat_listview_text_cell_data_function (GtkTreeViewColumn *col,
583 GtkCellRenderer *renderer,
584 GtkTreeModel *model,
585 GtkTreeIter *iter,
586 gpointer user_data)
587 {
588 Category *entry;
589 gchar *name;
590 gchar *string;
591
592 gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &entry, -1);
593 if(entry->key == 0)
594 name = _("(no category)");
595 else
596 name = entry->name;
597
598 gchar type = (entry->flags & GF_INCOME) ? '+' : '-';
599
600 #if MYDEBUG
601 string = g_markup_printf_escaped ("%d > [%d] %s [%c] %d", entry->key, entry->parent, name, type, entry->flags );
602 #else
603 if(entry->key == 0)
604 string = g_strdup(name);
605 else
606 {
607 if( entry->parent == 0 )
608 string = g_markup_printf_escaped("%s [%c]", name, type);
609 else
610 string = g_markup_printf_escaped(" %c <i>%s</i>", type, name);
611 //string = g_strdup_printf(" - %s", name);
612 }
613 #endif
614
615 //g_object_set(renderer, "text", string, NULL);
616 g_object_set(renderer, "markup", string, NULL);
617
618 g_free(string);
619
620 }
621
622
623 static void
624 ui_cat_listview_count_cell_data_function (GtkTreeViewColumn *col,
625 GtkCellRenderer *renderer,
626 GtkTreeModel *model,
627 GtkTreeIter *iter,
628 gpointer user_data)
629 {
630 Category *entry;
631 gchar buffer[256];
632
633 gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &entry, -1);
634 if(entry->usage_count > 0)
635 {
636 g_snprintf(buffer, 256-1, "%d", entry->usage_count);
637 g_object_set(renderer, "text", buffer, NULL);
638 }
639 else
640 g_object_set(renderer, "text", "", NULL);
641 }
642
643
644 /* = = = = = = = = = = = = = = = = */
645
646
647 void
648 ui_cat_listview_add(GtkTreeView *treeview, Category *item, GtkTreeIter *parent)
649 {
650 GtkTreeModel *model;
651 GtkTreeIter iter;
652 GtkTreePath *path;
653
654 DB( g_print ("ui_cat_listview_add()\n") );
655
656 if( item->name != NULL )
657 {
658 model = gtk_tree_view_get_model(treeview);
659
660 gtk_tree_store_append (GTK_TREE_STORE(model), &iter, parent);
661 gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
662 LST_DEFCAT_TOGGLE, FALSE,
663 LST_DEFCAT_DATAS, item,
664 LST_DEFCAT_NAME, item->name,
665 -1);
666
667 //select the added line
668
669 path = gtk_tree_model_get_path(model, &iter);
670 gtk_tree_view_expand_to_path (treeview, path);
671 gtk_tree_path_free(path);
672 gtk_tree_selection_select_iter (gtk_tree_view_get_selection(treeview), &iter);
673 }
674
675 }
676
677 Category *
678 ui_cat_listview_get_selected(GtkTreeView *treeview)
679 {
680 GtkTreeSelection *selection;
681 GtkTreeModel *model;
682 GtkTreeIter iter;
683
684 DB( g_print ("ui_cat_listview_get_selected()\n") );
685
686 selection = gtk_tree_view_get_selection(treeview);
687 if (gtk_tree_selection_get_selected(selection, &model, &iter))
688 {
689 Category *item;
690
691 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
692 if( item->key != 0 )
693 return item;
694 }
695 return NULL;
696 }
697
698 Category *
699 ui_cat_listview_get_selected_parent(GtkTreeView *treeview, GtkTreeIter *return_iter)
700 {
701 GtkTreeSelection *selection;
702 GtkTreeModel *model;
703 GtkTreeIter iter;
704 GtkTreePath *path;
705 Category *item;
706
707 DB( g_print ("ui_cat_listview_get_selected_parent()\n") );
708
709
710 selection = gtk_tree_view_get_selection(treeview);
711 if (gtk_tree_selection_get_selected(selection, &model, &iter))
712 {
713 path = gtk_tree_model_get_path(model, &iter);
714
715 DB( g_print ("path depth = %d\n", gtk_tree_path_get_depth(path)) );
716
717
718 if(gtk_tree_path_get_depth(path) > 1)
719 {
720 if( gtk_tree_path_up(path) )
721 {
722
723 DB( g_print ("up ok\n") );
724
725 if(gtk_tree_model_get_iter(model, &iter, path))
726 {
727
728 DB( g_print ("iter ok\n") );
729
730
731 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
732 if( item->key != 0 )
733 {
734 *return_iter = iter;
735 return item;
736 }
737 }
738 }
739 }
740 else
741 {
742
743 DB( g_print ("path <=1\n") );
744
745 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
746
747 if( item->key != 0 )
748 {
749 *return_iter = iter;
750 return item;
751 }
752
753
754 }
755 }
756 return NULL;
757 }
758
759 gboolean ui_cat_listview_remove (GtkTreeModel *model, guint32 key)
760 {
761 GtkTreeIter iter, child;
762 gboolean valid, cvalid;
763 Category *item;
764
765 DB( g_print("ui_cat_listview_remove() \n") );
766
767 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
768 while (valid)
769 {
770 gtk_tree_model_get (model, &iter, LST_DEFCAT_DATAS, &item, -1);
771
772 DB( g_print(" + item %p, %s\n", item, item->name) );
773
774 if(item->key == key || item->parent == key)
775 {
776 DB( g_print(" + removing cat %s\n", item->name) );
777 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
778 }
779
780 // iter children
781 cvalid = gtk_tree_model_iter_children (GTK_TREE_MODEL(model), &child, &iter);
782 while(cvalid)
783 {
784 gtk_tree_model_get(GTK_TREE_MODEL(model), &child, LST_DEFCAT_DATAS, &item, -1);
785 if(item->key == key || item->parent == key)
786 {
787 DB( g_print(" + removing subcat %s\n", item->name) );
788 gtk_tree_store_remove(GTK_TREE_STORE(model), &child);
789 }
790
791 cvalid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &child);
792 }
793 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
794 }
795
796 return TRUE;
797 }
798
799
800
801 void
802 ui_cat_listview_remove_selected(GtkTreeView *treeview)
803 {
804 GtkTreeSelection *selection;
805 GtkTreeModel *model;
806 GtkTreeIter iter;
807
808 DB( g_print("ui_cat_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_tree_store_remove(GTK_TREE_STORE(model), &iter);
814 }
815 }
816
817
818 static gboolean
819 ui_cat_listview_get_top_level (GtkTreeModel *liststore, guint32 key, GtkTreeIter *return_iter)
820 {
821 GtkTreeIter iter;
822 gboolean valid;
823 Category *item;
824
825 DB( g_print("ui_cat_listview_get_top_level() \n") );
826
827 if( liststore != NULL )
828 {
829 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter);
830 while (valid)
831 {
832 gtk_tree_model_get (liststore, &iter, LST_DEFCAT_DATAS, &item, -1);
833
834 if(item->key == key)
835 {
836 *return_iter = iter;
837 return TRUE;
838 }
839
840 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter);
841 }
842 }
843
844 return FALSE;
845 }
846
847
848 static void ui_cat_listview_populate_cat_ghfunc(gpointer key, gpointer value, struct catPopContext *ctx)
849 {
850 GtkTreeIter toplevel;
851 Category *item = value;
852 gint item_type;
853
854 item_type = (item->flags & GF_INCOME) ? CAT_TYPE_INCOME : CAT_TYPE_EXPENSE;
855
856 //DB( g_print("cat listview populate: %d %s\n", (guint32 *)key, item->name) );
857 if( (ctx->type == CAT_TYPE_ALL) || ctx->type == item_type || item->key == 0 )
858 {
859 if( item->parent == 0 )
860 {
861 gtk_tree_store_append (GTK_TREE_STORE(ctx->model), &toplevel, NULL);
862
863 gtk_tree_store_set (GTK_TREE_STORE(ctx->model), &toplevel,
864 LST_DEFCAT_TOGGLE , FALSE,
865 LST_DEFCAT_DATAS, item,
866 LST_DEFCAT_NAME, item->name,
867 -1);
868 }
869 }
870
871 }
872
873
874 static void ui_cat_listview_populate_subcat_ghfunc(gpointer key, gpointer value, struct catPopContext *ctx)
875 {
876 GtkTreeIter toplevel, child;
877 Category *item = value;
878 gboolean ret;
879 gint item_type;
880
881 item_type = (item->flags & GF_INCOME) ? CAT_TYPE_INCOME : CAT_TYPE_EXPENSE;
882
883 if( (ctx->type == CAT_TYPE_ALL) || ctx->type == item_type)
884 {
885 if( item->parent != 0 )
886 {
887 ret = ui_cat_listview_get_top_level(ctx->model, item->parent, &toplevel);
888 if( ret == TRUE )
889 {
890 gtk_tree_store_append (GTK_TREE_STORE(ctx->model), &child, &toplevel);
891
892 gtk_tree_store_set (GTK_TREE_STORE(ctx->model), &child,
893 LST_DEFCAT_TOGGLE , FALSE,
894 LST_DEFCAT_DATAS, item,
895 LST_DEFCAT_NAME, item->name,
896 -1);
897 }
898 }
899 }
900
901 }
902
903
904 static void ui_cat_listview_sort_force(GtkTreeSortable *sortable, gpointer user_data)
905 {
906 gint sort_column_id;
907 GtkSortType order;
908
909 DB( g_print("ui_cat_listview_sort_force()\n") );
910
911 gtk_tree_sortable_get_sort_column_id(sortable, &sort_column_id, &order);
912 DB( g_print(" - id %d order %d\n", sort_column_id, order) );
913
914 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortable), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, order);
915 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortable), sort_column_id, order);
916 }
917
918
919 void ui_cat_listview_populate(GtkWidget *view, gint type)
920 {
921 GtkTreeModel *model;
922 struct catPopContext ctx = { 0 };
923
924 DB( g_print("ui_cat_listview_populate() \n") );
925
926
927 model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
928
929 gtk_tree_store_clear (GTK_TREE_STORE(model));
930
931 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
932 gtk_tree_view_set_model(GTK_TREE_VIEW(view), NULL); /* Detach model from view */
933
934 /* clear and populate */
935 ctx.model = model;
936 ctx.type = type;
937
938 /* we have to do this in 2 times to ensure toplevel (cat) will be added before childs */
939 /* populate cat 1st */
940 g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_cat_ghfunc, &ctx);
941 g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_subcat_ghfunc, &ctx);
942
943
944 gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); /* Re-attach model to view */
945 g_object_unref(model);
946
947 gtk_tree_view_expand_all (GTK_TREE_VIEW(view));
948
949 }
950
951
952 static gboolean ui_cat_listview_search_equal_func (GtkTreeModel *model,
953 gint column,
954 const gchar *key,
955 GtkTreeIter *iter,
956 gpointer search_data)
957 {
958 gboolean retval = TRUE;
959 gchar *normalized_string;
960 gchar *normalized_key;
961 gchar *case_normalized_string = NULL;
962 gchar *case_normalized_key = NULL;
963 Category *item;
964
965 //gtk_tree_model_get_value (model, iter, column, &value);
966 gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &item, -1);
967
968 if(item != NULL)
969 {
970 normalized_string = g_utf8_normalize (item->name, -1, G_NORMALIZE_ALL);
971 normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
972
973 if (normalized_string && normalized_key)
974 {
975 case_normalized_string = g_utf8_casefold (normalized_string, -1);
976 case_normalized_key = g_utf8_casefold (normalized_key, -1);
977
978 if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
979 retval = FALSE;
980 }
981
982 g_free (normalized_key);
983 g_free (normalized_string);
984 g_free (case_normalized_key);
985 g_free (case_normalized_string);
986 }
987 return retval;
988 }
989
990
991 GtkWidget *
992 ui_cat_listview_new(gboolean withtoggle, gboolean withcount)
993 {
994 GtkTreeStore *store;
995 GtkWidget *treeview;
996 GtkCellRenderer *renderer;
997 GtkTreeViewColumn *column;
998
999 DB( g_print("ui_cat_listview_new() \n") );
1000
1001 store = gtk_tree_store_new(
1002 NUM_LST_DEFCAT,
1003 G_TYPE_BOOLEAN,
1004 G_TYPE_POINTER,
1005 G_TYPE_STRING
1006 );
1007
1008 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1009 g_object_unref(store);
1010
1011 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (treeview), PREFS->grid_lines);
1012
1013
1014 // column 1: toggle
1015 if( withtoggle == TRUE )
1016 {
1017 renderer = gtk_cell_renderer_toggle_new ();
1018 column = gtk_tree_view_column_new_with_attributes (_("Visible"),
1019 renderer, "active", LST_DEFCAT_TOGGLE, NULL);
1020 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
1021
1022 g_signal_connect (G_OBJECT(renderer), "toggled",
1023 G_CALLBACK (ui_cat_listview_fixed_toggled), store);
1024
1025 }
1026
1027 // column 2: name
1028 renderer = gtk_cell_renderer_text_new ();
1029 g_object_set(renderer,
1030 "ellipsize", PANGO_ELLIPSIZE_END,
1031 "ellipsize-set", TRUE,
1032 NULL);
1033
1034 column = gtk_tree_view_column_new();
1035 gtk_tree_view_column_set_title(column, _("Name"));
1036 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1037 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_cat_listview_text_cell_data_function, GINT_TO_POINTER(LST_DEFCAT_NAME), NULL);
1038 gtk_tree_view_column_set_alignment (column, 0.5);
1039 gtk_tree_view_column_set_min_width(column, HB_MINWIDTH_LIST);
1040 gtk_tree_view_column_set_sort_column_id (column, LST_DEFCAT_SORT_NAME);
1041 gtk_tree_view_column_set_resizable(column, TRUE);
1042 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
1043
1044 if( withcount == TRUE )
1045 {
1046 column = gtk_tree_view_column_new();
1047 gtk_tree_view_column_set_title(column, _("Usage"));
1048 renderer = gtk_cell_renderer_text_new ();
1049 g_object_set(renderer, "xalign", 0.5, NULL);
1050 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1051 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_cat_listview_count_cell_data_function, GINT_TO_POINTER(LST_DEFCAT_DATAS), NULL);
1052 gtk_tree_view_column_set_alignment (column, 0.5);
1053 gtk_tree_view_column_set_sort_column_id (column, LST_DEFCAT_SORT_USED);
1054 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
1055 }
1056
1057
1058 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), ui_cat_listview_search_equal_func, NULL, NULL);
1059
1060 // treeview attribute
1061 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), withcount);
1062
1063 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_SORT_NAME, ui_cat_listview_compare_func, GINT_TO_POINTER(LST_DEFCAT_SORT_NAME), NULL);
1064 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_SORT_USED, ui_cat_listview_compare_func, GINT_TO_POINTER(LST_DEFCAT_SORT_USED), NULL);
1065
1066 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), LST_DEFCAT_SORT_NAME, GTK_SORT_ASCENDING);
1067
1068 return treeview;
1069 }
1070
1071
1072 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1073
1074 /**
1075 * ui_cat_manage_filter_text_handler
1076 *
1077 * filter to entry to avoid seizure of ':' char
1078 *
1079 */
1080 static void ui_cat_manage_filter_text_handler (GtkEntry *entry,
1081 const gchar *text,
1082 gint length,
1083 gint *position,
1084 gpointer data)
1085 {
1086 GtkEditable *editable = GTK_EDITABLE(entry);
1087 gint i, count=0;
1088 gchar *result = g_new0 (gchar, length+1);
1089
1090 for (i=0; i < length; i++)
1091 {
1092 if (text[i]==':')
1093 continue;
1094 result[count++] = text[i];
1095 }
1096
1097
1098 if (count > 0) {
1099 g_signal_handlers_block_by_func (G_OBJECT (editable),
1100 G_CALLBACK (ui_cat_manage_filter_text_handler),
1101 data);
1102 gtk_editable_insert_text (editable, result, count, position);
1103 g_signal_handlers_unblock_by_func (G_OBJECT (editable),
1104 G_CALLBACK (ui_cat_manage_filter_text_handler),
1105 data);
1106 }
1107 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert_text");
1108
1109 g_free (result);
1110 }
1111
1112
1113 static void
1114 ui_cat_manage_dialog_delete_unused( GtkWidget *widget, gpointer user_data)
1115 {
1116 struct ui_cat_manage_dialog_data *data = user_data;
1117 gboolean result;
1118
1119 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
1120
1121 DB( g_print("(ui_cat_manage_dialog) delete unused - data %p\n", data) );
1122
1123 result = ui_dialog_msg_confirm_alert(
1124 GTK_WINDOW(data->window),
1125 _("Delete unused categories"),
1126 _("Are you sure you want to permanently\ndelete unused categories?"),
1127 _("_Delete")
1128 );
1129
1130 if( result == GTK_RESPONSE_OK )
1131 {
1132 GtkTreeModel *model;
1133
1134 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat));
1135 gtk_tree_store_clear (GTK_TREE_STORE(model));
1136
1137 category_delete_unused();
1138
1139 ui_cat_manage_populate_listview (data);
1140 }
1141 }
1142
1143
1144
1145 /**
1146 * ui_cat_manage_dialog_load_csv:
1147 *
1148 */
1149 static void
1150 ui_cat_manage_dialog_load_csv( GtkWidget *widget, gpointer user_data)
1151 {
1152 struct ui_cat_manage_dialog_data *data = user_data;
1153 gchar *filename = NULL;
1154 gchar *error;
1155
1156 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
1157
1158 DB( g_print("(ui_cat_manage_dialog) load csv - data %p\n", data) );
1159
1160 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_OPEN, &filename, NULL) == TRUE )
1161 {
1162 DB( g_print(" + filename is %s\n", filename) );
1163
1164 if(!category_load_csv(filename, &error))
1165 {
1166 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
1167 _("File format error"),
1168 _("The CSV file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.")
1169 );
1170 }
1171
1172 g_free( filename );
1173 ui_cat_manage_populate_listview(data);
1174 }
1175
1176 }
1177
1178 /**
1179 * ui_cat_manage_dialog_save_csv:
1180 *
1181 */
1182 static void
1183 ui_cat_manage_dialog_save_csv( GtkWidget *widget, gpointer user_data)
1184 {
1185 struct ui_cat_manage_dialog_data *data = user_data;
1186 gchar *filename = NULL;
1187 gchar *error;
1188
1189 DB( g_print("(defcategory) save csv\n") );
1190
1191 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1192
1193 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, NULL) == TRUE )
1194 {
1195 DB( g_print(" + filename is %s\n", filename) );
1196
1197 category_save_csv(filename, &error);
1198 g_free( filename );
1199 }
1200 }
1201
1202 /**
1203 * ui_cat_manage_dialog_add:
1204 *
1205 * add an empty new category/subcategory
1206 *
1207 */
1208 static void
1209 ui_cat_manage_dialog_add(GtkWidget *widget, gpointer user_data)
1210 {
1211 struct ui_cat_manage_dialog_data *data;
1212 gboolean subcat = GPOINTER_TO_INT(user_data);
1213 const gchar *name;
1214 //GtkTreeModel *model;
1215 GtkTreeIter parent_iter;
1216 GtkWidget *tmpwidget;
1217 Category *item, *paritem;
1218 gint type;
1219
1220 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1221 DB( g_print("\n(defcategory) add (data=%p) is subcat=%d\n", data, subcat) );
1222
1223 tmpwidget = (subcat == FALSE ? data->ST_name1 : data->ST_name2);
1224 name = gtk_entry_get_text(GTK_ENTRY(tmpwidget));
1225 //model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat));
1226
1227 /* ignore if item is empty */
1228 if (name && *name)
1229 {
1230 data->change++;
1231
1232 item = da_cat_malloc();
1233 item->name = g_strdup(name);
1234
1235 g_strstrip(item->name);
1236
1237 /* if cat use new id */
1238 if(subcat == FALSE)
1239 {
1240 type = radio_get_active(GTK_CONTAINER(data->RA_type));
1241 if(type == 1)
1242 item->flags |= GF_INCOME;
1243
1244 if( da_cat_append(item) )
1245 {
1246 DB( g_print(" => add cat: %p %d, %s type=%d\n", item, subcat, item->name, type) );
1247 ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), item, NULL);
1248 }
1249 }
1250 /* if subcat use parent id & gf_income */
1251 else
1252 {
1253 paritem = ui_cat_listview_get_selected_parent(GTK_TREE_VIEW(data->LV_cat), &parent_iter);
1254 if(paritem)
1255 {
1256 DB( g_print(" => selitem parent: %d, %s\n", paritem->key, paritem->name) );
1257
1258 item->parent = paritem->key;
1259 item->flags |= (paritem->flags & GF_INCOME);
1260 item->flags |= GF_SUB;
1261
1262 if(da_cat_append(item))
1263 {
1264 DB( g_print(" => add subcat: %p %d, %s\n", item, subcat, item->name) );
1265 ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), item, &parent_iter);
1266 }
1267 }
1268 }
1269
1270 gtk_entry_set_text(GTK_ENTRY(tmpwidget),"");
1271 }
1272 }
1273
1274
1275 static void ui_cat_manage_dialog_edit_entry_cb(GtkEditable *editable, gpointer user_data)
1276 {
1277 GtkDialog *window = user_data;
1278 const gchar *buffer;
1279
1280 buffer = gtk_entry_get_text(GTK_ENTRY(editable));
1281 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, strlen(buffer) > 0 ? TRUE : FALSE);
1282 }
1283
1284
1285 static void ui_cat_manage_dialog_edit(GtkWidget *widget, gpointer user_data)
1286 {
1287 struct ui_cat_manage_dialog_data *data;
1288 GtkWidget *dialog, *content, *mainvbox, *w_name, *w_type = NULL;
1289 GtkTreeSelection *selection;
1290 GtkTreeModel *model;
1291 GtkTreeIter iter;
1292
1293 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1294 DB( g_print("\n(defcategory) edit\n") );
1295
1296 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat));
1297 //if true there is a selected node
1298 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1299 {
1300 Category *item;
1301
1302 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
1303
1304 dialog = gtk_dialog_new_with_buttons (_("Edit..."),
1305 GTK_WINDOW (data->window),
1306 0,
1307 _("_Cancel"),
1308 GTK_RESPONSE_REJECT,
1309 _("_OK"),
1310 GTK_RESPONSE_ACCEPT,
1311 NULL);
1312
1313 content = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
1314 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1315 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1316 gtk_container_set_border_width (GTK_CONTAINER (mainvbox), SPACING_MEDIUM);
1317
1318 w_name = gtk_entry_new();
1319 gtk_box_pack_start (GTK_BOX (mainvbox), w_name, TRUE, TRUE, 0);
1320
1321 gtk_entry_set_text(GTK_ENTRY(w_name), item->name);
1322 gtk_widget_grab_focus (w_name);
1323
1324 gtk_entry_set_activates_default (GTK_ENTRY(w_name), TRUE);
1325
1326 if(!(item->flags & GF_SUB))
1327 {
1328 w_type = gtk_check_button_new_with_mnemonic(_("_Income"));
1329 gtk_box_pack_start (GTK_BOX (mainvbox), w_type, TRUE, TRUE, 0);
1330 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_type), item->flags & GF_INCOME ? TRUE : FALSE);
1331 }
1332
1333 g_signal_connect (G_OBJECT (w_name), "changed", G_CALLBACK (ui_cat_manage_dialog_edit_entry_cb), dialog);
1334
1335
1336 gtk_widget_show_all(mainvbox);
1337
1338 gtk_dialog_set_default_response(GTK_DIALOG( dialog ), GTK_RESPONSE_ACCEPT);
1339
1340 //wait for the user
1341 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1342
1343 if(result == GTK_RESPONSE_ACCEPT)
1344 {
1345 const gchar *name;
1346
1347 // 1: manage renaming
1348 name = gtk_entry_get_text(GTK_ENTRY(w_name));
1349 // ignore if item is empty
1350 if (name && *name)
1351 {
1352 if( category_rename(item, name) )
1353 {
1354 //to redraw the active entry
1355 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_cat));
1356 data->change++;
1357 }
1358 else
1359 {
1360 Category *parent;
1361 gchar *fromname, *toname = NULL;
1362
1363 fromname = da_cat_get_fullname(item);
1364
1365 if( item->parent == 0)
1366 toname = g_strdup(name);
1367 else
1368 {
1369 parent = da_cat_get(item->parent);
1370 if( parent )
1371 {
1372 toname = g_strdup_printf("%s:%s", parent->name, name);
1373 }
1374 }
1375
1376
1377 ui_dialog_msg_infoerror(GTK_WINDOW(dialog), GTK_MESSAGE_ERROR,
1378 _("Error"),
1379 _("Cannot rename this Category,\n"
1380 "from '%s' to '%s',\n"
1381 "this name already exists."),
1382 fromname,
1383 toname
1384 );
1385
1386 g_free(fromname);
1387 g_free(toname);
1388
1389 }
1390 }
1391
1392 // 2: manage flag change
1393 if(!(item->flags & GF_SUB))
1394 {
1395 gboolean isIncome;
1396
1397 isIncome = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_type));
1398 data->change += category_change_type(item, isIncome);
1399 }
1400
1401 ui_cat_listview_sort_force(GTK_TREE_SORTABLE(model), NULL);
1402 }
1403
1404 // cleanup and destroy
1405 gtk_widget_destroy (dialog);
1406 }
1407
1408 }
1409
1410
1411 static void ui_cat_manage_dialog_merge_entry_cb(GtkComboBox *widget, gpointer user_data)
1412 {
1413 GtkDialog *window = user_data;
1414 gchar *buffer;
1415
1416 buffer = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (widget))));
1417 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_OK, strlen(buffer) > 0 ? TRUE : FALSE);
1418 }
1419
1420
1421 static void ui_cat_manage_dialog_merge(GtkWidget *widget, gpointer user_data)
1422 {
1423 struct ui_cat_manage_dialog_data *data;
1424 GtkWidget *dialog, *content, *mainvbox;
1425 GtkWidget *getwidget, *togglebutton;
1426 GtkTreeSelection *selection;
1427 GtkTreeModel *model;
1428 GtkTreeIter iter;
1429
1430 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1431 DB( g_print("(defcategory) merge\n") );
1432
1433 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat));
1434 //if true there is a selected node
1435 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1436 {
1437 Category *srccat;
1438 gchar *title;
1439 gchar *secondtext;
1440
1441 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &srccat, -1);
1442
1443 title = g_strdup_printf (
1444 _("Merge category '%s'"), srccat->name);
1445
1446 dialog = gtk_message_dialog_new (GTK_WINDOW (data->window),
1447 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1448 GTK_MESSAGE_WARNING,
1449 GTK_BUTTONS_NONE,
1450 title,
1451 NULL
1452 );
1453
1454 gtk_dialog_add_buttons (GTK_DIALOG(dialog),
1455 _("_Cancel"), GTK_RESPONSE_CANCEL,
1456 _("Merge"), GTK_RESPONSE_OK,
1457 NULL);
1458
1459 gtk_dialog_set_default_response(GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
1460
1461 content = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG (dialog));
1462 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
1463 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1464
1465 secondtext = _("Transactions assigned to this category,\n"
1466 "will be moved to the category selected below.");
1467
1468 g_object_set(GTK_MESSAGE_DIALOG (dialog), "secondary-text", secondtext, NULL);
1469 g_free(title);
1470
1471 getwidget = ui_cat_comboboxentry_new(NULL);
1472 gtk_box_pack_start (GTK_BOX (mainvbox), getwidget, FALSE, FALSE, 0);
1473
1474 secondtext = g_strdup_printf (
1475 _("_Delete the category '%s'"), srccat->name);
1476 togglebutton = gtk_check_button_new_with_mnemonic(secondtext);
1477 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton), TRUE);
1478 g_free(secondtext);
1479 gtk_box_pack_start (GTK_BOX (mainvbox), togglebutton, FALSE, FALSE, 0);
1480
1481 //setup
1482 //gtk_combo_box_set_active(GTK_COMBO_BOX(getwidget), oldpos);
1483 g_signal_connect (G_OBJECT (getwidget), "changed", G_CALLBACK (ui_cat_manage_dialog_merge_entry_cb), dialog);
1484 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE);
1485
1486 ui_cat_comboboxentry_populate_except(GTK_COMBO_BOX(getwidget), GLOBALS->h_cat, srccat->key);
1487 gtk_widget_grab_focus (getwidget);
1488
1489 gtk_widget_show_all(mainvbox);
1490
1491 //wait for the user
1492 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1493
1494 if(result == GTK_RESPONSE_OK)
1495 {
1496 GtkTreeModel *model;
1497 Category *newcat, *parent;
1498 guint dstcatkey;
1499
1500
1501 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat));
1502 gtk_tree_store_clear (GTK_TREE_STORE(model));
1503
1504 dstcatkey = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(getwidget));
1505
1506 DB( g_print(" -> move cat to %d\n", dstcatkey) );
1507
1508 category_move(srccat->key, dstcatkey);
1509
1510 newcat = da_cat_get (dstcatkey);
1511
1512 //keep the income type with us
1513 parent = da_cat_get(srccat->parent);
1514 if(parent != NULL && (parent->flags & GF_INCOME))
1515 newcat->flags |= GF_INCOME;
1516
1517 //add the new category into listview
1518 if(newcat)
1519 ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), newcat, NULL);
1520
1521 // delete the old category
1522 if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)) )
1523 {
1524 DB( g_print(" -> delete %d '%s'\n", srccat->key, srccat->name ) );
1525
1526 da_cat_remove(srccat->key);
1527 ui_cat_listview_remove_selected(GTK_TREE_VIEW(data->LV_cat));
1528 }
1529
1530
1531 data->change++;
1532
1533 ui_cat_manage_populate_listview(data);
1534
1535 }
1536
1537 // cleanup and destroy
1538 gtk_widget_destroy (dialog);
1539 }
1540
1541 }
1542
1543
1544 /*
1545 ** delete the selected payee to our treeview and temp GList
1546 */
1547 static void ui_cat_manage_dialog_delete(GtkWidget *widget, gpointer user_data)
1548 {
1549 struct ui_cat_manage_dialog_data *data;
1550 Category *item;
1551 gint result;
1552
1553 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1554 DB( g_print("\n(defcategory) delete (data=%x)\n", (guint)data) );
1555
1556 item = ui_cat_listview_get_selected(GTK_TREE_VIEW(data->LV_cat));
1557 if( item != NULL )
1558 {
1559 gchar *title = NULL;
1560 gchar *secondtext = NULL;
1561
1562 title = g_strdup_printf (
1563 _("Are you sure you want to permanently delete '%s'?"), item->name);
1564
1565 if( item->usage_count > 0 )
1566 {
1567 secondtext = _("This category is used.\n"
1568 "Any transaction using that category will be set to (no category)");
1569 }
1570
1571 result = ui_dialog_msg_confirm_alert(
1572 GTK_WINDOW(data->window),
1573 title,
1574 secondtext,
1575 _("_Delete")
1576 );
1577
1578 g_free(title);
1579
1580 if( result == GTK_RESPONSE_OK )
1581 {
1582 category_move(item->key, 0);
1583 ui_cat_listview_remove(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat)), item->key);
1584 da_cat_remove(item->key);
1585 data->change++;
1586 }
1587
1588 }
1589 }
1590
1591
1592
1593 static void ui_cat_manage_dialog_expand_all(GtkWidget *widget, gpointer user_data)
1594 {
1595 struct ui_cat_manage_dialog_data *data;
1596
1597 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1598 DB( g_print("\n(defcategory) expand all (data=%x)\n", (guint)data) );
1599
1600 gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_cat));
1601
1602 }
1603
1604
1605 static void ui_cat_manage_dialog_collapse_all(GtkWidget *widget, gpointer user_data)
1606 {
1607 struct ui_cat_manage_dialog_data *data;
1608
1609 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1610 DB( g_print("\n(defcategory) collapse all (data=%x)\n", (guint)data) );
1611
1612 gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_cat));
1613
1614 }
1615
1616
1617 static void ui_cat_manage_dialog_update(GtkWidget *treeview, gpointer user_data)
1618 {
1619 struct ui_cat_manage_dialog_data *data;
1620 //gint count;
1621 gboolean selected, sensitive;
1622 GtkTreeSelection *selection;
1623 GtkTreeModel *model;
1624 GtkTreeIter iter;
1625 GtkTreePath *path;
1626 gchar *category;
1627 gboolean haschild = FALSE;
1628
1629 DB( g_print("ui_cat_manage_dialog_update()\n") );
1630
1631 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
1632 //window = gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW);
1633 //DB( g_print("(defpayee) widget=%08lx, window=%08lx, inst_data=%08lx\n", treeview, window, data) );
1634
1635 //if true there is a selected node
1636 selected = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)), &model, &iter);
1637
1638 DB( g_print(" selected = %d\n", selected) );
1639
1640 if(selected)
1641 {
1642 //path 0 active ?
1643 gtk_tree_model_get_iter_first(model, &iter);
1644 if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)), &iter))
1645 {
1646 DB( g_print(" 0 active = %d\n", 1) );
1647 selected = FALSE;
1648 }
1649 }
1650
1651 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1652
1653 //count = gtk_tree_selection_count_selected_rows(selection);
1654 //DB( g_print(" => select count=%d\n", count) );
1655
1656 category = NULL;
1657 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1658 {
1659 gchar *tree_path_str;
1660 Category *item;
1661
1662 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1663 LST_DEFCAT_DATAS, &item,
1664 -1);
1665
1666 haschild = gtk_tree_model_iter_has_child(GTK_TREE_MODEL(model), &iter);
1667 DB( g_print(" => has child=%d\n", haschild) );
1668
1669
1670 path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)), &iter);
1671 tree_path_str = gtk_tree_path_to_string(path);
1672 DB( g_print(" => select is=%s, depth=%d (id=%d, %s) flags=%d\n",
1673 tree_path_str,
1674 gtk_tree_path_get_depth(path),
1675 item->key,
1676 item->name,
1677 item->flags
1678 ) );
1679 g_free(tree_path_str);
1680
1681 //get parent if subcategory selectd
1682 DB( g_print(" => get parent for title\n") );
1683 if(gtk_tree_path_get_depth(path) != 1)
1684 gtk_tree_path_up(path);
1685
1686 if(gtk_tree_model_get_iter(model, &iter, path))
1687 {
1688 Category *tmpitem;
1689
1690 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1691 LST_DEFCAT_DATAS, &tmpitem,
1692 -1);
1693
1694 if(tmpitem->key > 0)
1695 category = tmpitem->name;
1696
1697 DB( g_print(" => parent is %s\n", category) );
1698
1699 }
1700
1701 gtk_tree_path_free(path);
1702
1703 }
1704
1705 gtk_label_set_text(GTK_LABEL(data->LA_category), category);
1706
1707 sensitive = (selected == TRUE) ? TRUE : FALSE;
1708 gtk_widget_set_sensitive(data->ST_name2, sensitive);
1709 gtk_widget_set_sensitive(data->BT_edit, sensitive);
1710 gtk_widget_set_sensitive(data->BT_merge, sensitive);
1711
1712 //avoid removing top categories
1713 sensitive = (haschild == TRUE) ? FALSE : sensitive;
1714
1715 gtk_widget_set_sensitive(data->BT_delete, sensitive);
1716 }
1717
1718
1719 /*
1720 **
1721 */
1722 static void ui_cat_manage_dialog_selection(GtkTreeSelection *treeselection, gpointer user_data)
1723 {
1724 ui_cat_manage_dialog_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), NULL);
1725 }
1726
1727 static void ui_cat_manage_dialog_onRowActivated (GtkTreeView *treeview,
1728 GtkTreePath *path,
1729 GtkTreeViewColumn *col,
1730 gpointer user_data)
1731 {
1732 GtkTreeModel *model;
1733 GtkTreeIter iter;
1734
1735 DB( g_print("ui_cat_manage_dialog_onRowActivated()\n") );
1736
1737
1738 model = gtk_tree_view_get_model(treeview);
1739 gtk_tree_model_get_iter_first(model, &iter);
1740 if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), &iter) == FALSE)
1741 {
1742 ui_cat_manage_dialog_edit(GTK_WIDGET(treeview), NULL);
1743 }
1744 }
1745
1746
1747 static gboolean ui_cat_manage_dialog_cleanup(struct ui_cat_manage_dialog_data *data, gint result)
1748 {
1749 gboolean doupdate = FALSE;
1750
1751 DB( g_print("(defcategory) cleanup\n") );
1752
1753 if(result == GTK_RESPONSE_ACCEPT)
1754 {
1755
1756 //do_application_specific_something ();
1757 DB( g_print(" accept\n") );
1758
1759
1760 GLOBALS->changes_count += data->change;
1761 }
1762
1763 DB( g_print(" free tmp_list\n") );
1764
1765 //da_category_destroy(data->tmp_list);
1766
1767 return doupdate;
1768 }
1769
1770
1771 static void ui_cat_manage_populate_listview(struct ui_cat_manage_dialog_data *data)
1772 {
1773 gint type;
1774
1775 type = radio_get_active(GTK_CONTAINER(data->RA_type)) == 1 ? CAT_TYPE_INCOME : CAT_TYPE_EXPENSE;
1776 ui_cat_listview_populate(data->LV_cat, type);
1777 gtk_tree_view_expand_all (GTK_TREE_VIEW(data->LV_cat));
1778 }
1779
1780
1781 /*
1782 **
1783 */
1784 static void ui_cat_manage_dialog_setup(struct ui_cat_manage_dialog_data *data)
1785 {
1786
1787 DB( g_print("(defcategory) setup\n") );
1788
1789 //init GList
1790 data->tmp_list = NULL; //data->tmp_list = hb-glist_clone_list(GLOBALS->cat_list, sizeof(struct _Group));
1791 data->change = 0;
1792
1793 //debug
1794 //da_cat_debug_list();
1795
1796 ui_cat_manage_populate_listview(data);
1797
1798 }
1799
1800
1801 static void ui_cat_manage_type_changed_cb (GtkToggleButton *button, gpointer user_data)
1802 {
1803 ui_cat_manage_populate_listview(user_data);
1804 //g_print(" toggle type=%d\n", gtk_toggle_button_get_active(button));
1805 }
1806
1807
1808 GtkWidget *ui_cat_manage_dialog (void)
1809 {
1810 struct ui_cat_manage_dialog_data data;
1811 GtkWidget *window, *content, *mainvbox, *bbox, *table, *hbox, *vbox, *label, *scrollwin, *treeview;
1812 GtkWidget *menu, *menuitem, *widget, *image, *tbar;
1813 GtkToolItem *toolitem;
1814 gint w, h, row;
1815
1816 window = gtk_dialog_new_with_buttons (_("Manage Categories"),
1817 GTK_WINDOW(GLOBALS->mainwindow),
1818 0,
1819 _("_Close"),
1820 GTK_RESPONSE_ACCEPT,
1821 NULL);
1822
1823 data.window = window;
1824 data.change = 0;
1825
1826 gtk_window_set_icon_name(GTK_WINDOW (window), ICONNAME_HB_CATEGORY);
1827
1828 //set a nice dialog size
1829 gtk_window_get_size(GTK_WINDOW(GLOBALS->mainwindow), &w, &h);
1830 gtk_window_set_default_size (GTK_WINDOW(window), -1, h/PHI);
1831
1832
1833 //store our window private data
1834 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)&data);
1835 DB( g_print("(defcategory) window=%x, inst_data=%x\n", (guint)window, (guint)&data) );
1836
1837 g_signal_connect (window, "destroy",
1838 G_CALLBACK (gtk_widget_destroyed), &window);
1839
1840 //window contents
1841 content = gtk_dialog_get_content_area(GTK_DIALOG (window));
1842 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
1843 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1844 gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM);
1845
1846 //our table
1847 table = gtk_grid_new ();
1848 gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL);
1849 gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM);
1850 gtk_box_pack_start (GTK_BOX (mainvbox), table, TRUE, TRUE, 0);
1851
1852 row = 0;
1853 bbox = make_radio(CYA_CAT_TYPE, TRUE, GTK_ORIENTATION_HORIZONTAL);
1854 data.RA_type = bbox;
1855 gtk_widget_set_halign (bbox, GTK_ALIGN_CENTER);
1856 gtk_grid_attach (GTK_GRID (table), bbox, 0, row, 2, 1);
1857
1858 widget = radio_get_nth_widget(GTK_CONTAINER(bbox), 1);
1859 if(widget)
1860 g_signal_connect (widget, "toggled", G_CALLBACK (ui_cat_manage_type_changed_cb), &data);
1861
1862 menu = gtk_menu_new ();
1863 gtk_widget_set_halign (menu, GTK_ALIGN_END);
1864
1865 menuitem = gtk_menu_item_new_with_mnemonic (_("_Import CSV"));
1866 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1867 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_cat_manage_dialog_load_csv), &data);
1868
1869 menuitem = gtk_menu_item_new_with_mnemonic (_("E_xport CSV"));
1870 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1871 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_cat_manage_dialog_save_csv), &data);
1872
1873 menuitem = gtk_separator_menu_item_new();
1874 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1875
1876 menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete unused"));
1877 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1878 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_cat_manage_dialog_delete_unused), &data);
1879
1880 gtk_widget_show_all (menu);
1881
1882 widget = gtk_menu_button_new();
1883 image = gtk_image_new_from_icon_name (ICONNAME_HB_BUTTON_MENU, GTK_ICON_SIZE_MENU);
1884
1885 //gchar *thename;
1886 //gtk_image_get_icon_name(image, &thename, NULL);
1887 //g_print("the name is %s\n", thename);
1888
1889 g_object_set (widget, "image", image, "popup", GTK_MENU(menu), NULL);
1890 gtk_widget_set_halign (widget, GTK_ALIGN_END);
1891 gtk_grid_attach (GTK_GRID (table), widget, 1, row, 1, 1);
1892
1893 row++;
1894 widget = gtk_entry_new ();
1895 data.ST_name1 = widget;
1896 gtk_entry_set_placeholder_text(GTK_ENTRY(data.ST_name1), _("new category") );
1897 gtk_widget_set_hexpand (widget, TRUE);
1898 gtk_grid_attach (GTK_GRID (table), widget, 0, row, 2, 1);
1899
1900 // subcategory + add button
1901 row++;
1902 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
1903 gtk_grid_attach (GTK_GRID (table), hbox, 0, row, 2, 1);
1904 data.LA_category = gtk_label_new(NULL);
1905 gtk_box_pack_start (GTK_BOX (hbox), data.LA_category, FALSE, FALSE, 0);
1906 label = gtk_label_new(":");
1907 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1908 data.ST_name2 = gtk_entry_new ();
1909 gtk_entry_set_placeholder_text(GTK_ENTRY(data.ST_name2), _("new subcategory") );
1910 gtk_box_pack_start (GTK_BOX (hbox), data.ST_name2, TRUE, TRUE, 0);
1911
1912 //list
1913 row++;
1914 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1915 gtk_grid_attach (GTK_GRID (table), vbox, 0, row, 2, 1);
1916
1917 scrollwin = gtk_scrolled_window_new(NULL,NULL);
1918 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN);
1919 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1920 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrollwin), HB_MINHEIGHT_LIST);
1921 treeview = ui_cat_listview_new(FALSE, TRUE);
1922 data.LV_cat = treeview;
1923 gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
1924 gtk_widget_set_hexpand (scrollwin, TRUE);
1925 gtk_widget_set_vexpand (scrollwin, TRUE);
1926 gtk_box_pack_start (GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
1927
1928 //list toolbar
1929 tbar = gtk_toolbar_new();
1930 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
1931 gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
1932 gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
1933 gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0);
1934
1935 /*widget = gtk_tool_item_new ();
1936 label = gtk_label_new("test");
1937 gtk_container_add(GTK_CONTAINER(widget), label);
1938 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(widget), -1);*/
1939
1940 //hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1941 /*
1942 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1943 toolitem = gtk_tool_item_new();
1944 gtk_container_add (GTK_CONTAINER(toolitem), hbox);
1945 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
1946
1947 //widget = make_image_button("text-editor-symbolic", _("Edit"));
1948 widget = gtk_button_new_with_mnemonic(_("_Edit"));
1949 data.BT_edit = widget;
1950 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1951
1952 //widget = make_image_button("merge-symbolic", _("Merge"));
1953 widget = gtk_button_new_with_mnemonic(_("_Merge"));
1954 data.BT_merge = widget;
1955 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1956
1957 //widget = make_image_button(ICONNAME_SYM_EDIT_DELETE, _("Delete"));
1958 widget = gtk_button_new_with_mnemonic(_("_Delete"));
1959 data.BT_delete = widget;
1960 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1961 */
1962
1963 toolitem = gtk_separator_tool_item_new ();
1964 gtk_tool_item_set_expand (toolitem, TRUE);
1965 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
1966 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
1967
1968 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1969 toolitem = gtk_tool_item_new();
1970 gtk_container_add (GTK_CONTAINER(toolitem), hbox);
1971 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
1972
1973 widget = make_image_button(ICONNAME_HB_BUTTON_EXPAND, _("Expand all"));
1974 data.BT_expand = widget;
1975 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1976
1977 widget = make_image_button(ICONNAME_HB_BUTTON_COLLAPSE, _("Collapse all"));
1978 data.BT_collapse = widget;
1979 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1980
1981
1982 row++;
1983 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1984 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START);
1985 gtk_box_set_spacing (GTK_BOX (bbox), SPACING_SMALL);
1986 gtk_grid_attach (GTK_GRID (table), bbox, 0, row, 2, 1);
1987
1988 data.BT_edit = gtk_button_new_with_mnemonic(_("_Edit"));
1989 gtk_container_add (GTK_CONTAINER (bbox), data.BT_edit);
1990
1991 data.BT_merge = gtk_button_new_with_mnemonic(_("_Merge"));
1992 gtk_container_add (GTK_CONTAINER (bbox), data.BT_merge);
1993
1994 data.BT_delete = gtk_button_new_with_mnemonic(_("_Delete"));
1995 gtk_container_add (GTK_CONTAINER (bbox), data.BT_delete);
1996
1997
1998 /*row++;
1999 widget = gtk_check_button_new_with_mnemonic(_("I_ncome"));
2000 data.CM_type = widget;
2001 gtk_grid_attach (GTK_GRID (table), widget, 0, row, 3, 1);*/
2002
2003
2004 //connect all our signals
2005 g_signal_connect (G_OBJECT (data.ST_name1), "activate", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(FALSE));
2006 g_signal_connect (G_OBJECT (data.ST_name2), "activate", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(TRUE));
2007
2008 g_signal_connect(G_OBJECT(data.ST_name1), "insert-text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL);
2009 g_signal_connect(G_OBJECT(data.ST_name2), "insert-text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL);
2010
2011
2012 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_cat)), "changed", G_CALLBACK (ui_cat_manage_dialog_selection), NULL);
2013 g_signal_connect (GTK_TREE_VIEW(data.LV_cat), "row-activated", G_CALLBACK (ui_cat_manage_dialog_onRowActivated), NULL);
2014
2015 g_signal_connect (G_OBJECT (data.BT_edit), "clicked", G_CALLBACK (ui_cat_manage_dialog_edit), NULL);
2016 g_signal_connect (G_OBJECT (data.BT_merge), "clicked", G_CALLBACK (ui_cat_manage_dialog_merge), NULL);
2017 g_signal_connect (G_OBJECT (data.BT_delete), "clicked", G_CALLBACK (ui_cat_manage_dialog_delete), NULL);
2018
2019 g_signal_connect (G_OBJECT (data.BT_expand), "clicked", G_CALLBACK (ui_cat_manage_dialog_expand_all), NULL);
2020 g_signal_connect (G_OBJECT (data.BT_collapse), "clicked", G_CALLBACK (ui_cat_manage_dialog_collapse_all), NULL);
2021
2022 //setup, init and show window
2023 category_fill_usage();
2024 ui_cat_manage_dialog_setup(&data);
2025 ui_cat_manage_dialog_update(data.LV_cat, NULL);
2026
2027 gtk_widget_show_all (window);
2028
2029 //wait for the user
2030 gint result = gtk_dialog_run (GTK_DIALOG (window));
2031
2032 switch (result)
2033 {
2034 case GTK_RESPONSE_ACCEPT:
2035 //do_application_specific_something ();
2036 break;
2037 default:
2038 //do_nothing_since_dialog_was_cancelled ();
2039 break;
2040 }
2041
2042 // cleanup and destroy
2043 ui_cat_manage_dialog_cleanup(&data, result);
2044 gtk_widget_destroy (window);
2045
2046 GLOBALS->changes_count += data.change;
2047
2048 return NULL;
2049 }
2050
2051
2052
This page took 0.132282 seconds and 4 git commands to generate.