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