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