]> Dogcows Code - chaz/homebank/blob - src/ui-category.c
add gitignore
[chaz/homebank] / src / ui-category.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 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 #include "homebank.h"
21
22 #include "ui-category.h"
23
24 #define MYDEBUG 0
25
26 #if MYDEBUG
27 #define DB(x) (x);
28 #else
29 #define DB(x);
30 #endif
31
32 /* our global datas */
33 extern struct HomeBank *GLOBALS;
34
35 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
36
37 /**
38 * ui_cat_comboboxentry_get_name:
39 *
40 * get the name of the active category or -1
41 *
42 * Return value: a new allocated name tobe freed with g_free
43 *
44 */
45 gchar *
46 ui_cat_comboboxentry_get_name(GtkComboBox *entry_box)
47 {
48 gchar *cbname;
49 gchar *name = NULL;
50
51 DB( g_print ("ui_cat_comboboxentry_get_name()\n") );
52
53 cbname = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
54 if( cbname != NULL)
55 {
56 name = g_strdup(cbname);
57 g_strstrip(name);
58 }
59
60 return name;
61 }
62
63
64 /**
65 * ui_cat_comboboxentry_get_key:
66 *
67 * get the key of the active category or -1
68 *
69 * Return value: the key or -1
70 *
71 */
72 guint32
73 ui_cat_comboboxentry_get_key_add_new(GtkComboBox *entry_box)
74 {
75 Category *item;
76 gchar *name;
77
78 DB( g_print ("ui_cat_comboboxentry_get_key()\n") );
79
80 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
81
82 if( name == NULL)
83 return -1;
84
85 item = da_cat_get_by_fullname(name);
86 if(item == NULL)
87 {
88 /* automatic add */
89 //todo: check prefs + ask the user here 1st time
90 item = da_cat_append_ifnew_by_fullname(name, FALSE);
91
92 ui_cat_comboboxentry_add(entry_box, item);
93 }
94
95 return item->key;
96 }
97
98
99 /**
100 * ui_cat_comboboxentry_get_key:
101 *
102 * get the key of the active category or -1
103 *
104 * Return value: the key or -1
105 *
106 */
107 guint32
108 ui_cat_comboboxentry_get_key(GtkComboBox *entry_box)
109 {
110 Category *item;
111 gchar *name;
112
113 DB( g_print ("ui_cat_comboboxentry_get_key()\n") );
114
115 name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
116 if( name == NULL)
117 return -1;
118
119 item = da_cat_get_by_fullname(name);
120 if(item != NULL)
121 return item->key;
122
123 return -1;
124 }
125
126 gboolean
127 ui_cat_comboboxentry_set_active(GtkComboBox *entry_box, guint32 key)
128 {
129 Category *item;
130 gchar *fullname;
131
132 DB( g_print ("ui_cat_comboboxentry_set_active()\n") );
133
134
135 if( key > 0 )
136 {
137 item = da_cat_get(key);
138 if( item != NULL)
139 {
140 if( item->parent == 0)
141 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), item->name);
142 else
143 {
144 fullname = da_cat_get_fullname(item);
145 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), fullname);
146 g_free(fullname);
147 }
148 return TRUE;
149 }
150 }
151 gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))), "");
152 return FALSE;
153 }
154
155 /**
156 * ui_cat_comboboxentry_add:
157 *
158 * Add a single element (useful for dynamics add)
159 *
160 * Return value: --
161 *
162 */
163 void
164 ui_cat_comboboxentry_add(GtkComboBox *entry_box, Category *item)
165 {
166
167 DB( g_print ("ui_cat_comboboxentry_add()\n") );
168
169
170 DB( g_print (" -> try to add: '%s'\n", item->name) );
171
172 if( item->name != NULL )
173 {
174 GtkTreeModel *model;
175 GtkTreeIter iter;
176
177 gchar *fullname, *name;
178
179 fullname = da_cat_get_fullname(item);
180 model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box));
181
182 if( item->parent == 0 )
183 name = g_strdup(item->name);
184 else
185 name = g_strdup_printf(" - %s", item->name);
186
187 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
188 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
189 0, fullname,
190 1, name,
191 -1);
192
193 g_free(fullname);
194 g_free(name);
195
196 }
197 }
198
199
200 static void
201 ui_cat_comboboxentry_populate_ghfunc(gpointer key, gpointer value, struct catPopContext *ctx)
202 {
203 GtkTreeIter iter;
204 Category *item = value;
205 gchar *fullname, *name;
206 gchar type;
207
208 if( ( item->key != ctx->except_key ) )
209 {
210 type = (item->flags & GF_INCOME) ? '+' : '-';
211
212 fullname = da_cat_get_fullname(item);
213
214 //DB( g_print ("cat combo populate [%d:%d] %s\n", item->parent, item->key, fullname) );
215
216 if(item->key == 0)
217 name = g_strdup(item->name);
218 else
219 {
220 if( item->parent == 0 )
221 name = g_strdup_printf("%s [%c]", item->name, type);
222 else
223 name = g_strdup_printf(" %c %s", type, item->name);
224 }
225
226 gtk_list_store_append (GTK_LIST_STORE(ctx->model), &iter);
227 gtk_list_store_set (GTK_LIST_STORE(ctx->model), &iter,
228 0, fullname,
229 1, name,
230 2, item->parent == 0 ? 1 : 0,
231 -1);
232
233 g_free(fullname);
234 g_free(name);
235 }
236
237 }
238
239 /**
240 * ui_cat_comboboxentry_populate:
241 *
242 * Populate the list and completion
243 *
244 * Return value: --
245 *
246 */
247 void
248 ui_cat_comboboxentry_populate(GtkComboBox *entry_box, GHashTable *hash)
249 {
250 ui_cat_comboboxentry_populate_except(entry_box, hash, -1);
251 }
252
253 void
254 ui_cat_comboboxentry_populate_except(GtkComboBox *entry_box, GHashTable *hash, guint except_key)
255 {
256 GtkTreeModel *model;
257 GtkEntryCompletion *completion;
258 struct catPopContext ctx;
259
260 DB( g_print ("ui_cat_comboboxentry_populate()\n") );
261
262 model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box));
263 completion = gtk_entry_get_completion(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box))));
264
265 /* keep our model alive and detach from comboboxentry and completion */
266 g_object_ref(model);
267 gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), NULL);
268 gtk_entry_completion_set_model (completion, NULL);
269
270 /* clear and populate */
271 ctx.model = model;
272 ctx.except_key = except_key;
273
274 gtk_list_store_clear (GTK_LIST_STORE(model));
275 g_hash_table_foreach(hash, (GHFunc)ui_cat_comboboxentry_populate_ghfunc, &ctx);
276
277 /* reatach our model */
278 gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), model);
279 gtk_entry_completion_set_model (completion, model);
280 g_object_unref(model);
281
282 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
283
284 }
285
286
287
288 static gint
289 ui_cat_comboboxentry_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
290 {
291 gint retval = 0;
292 gchar *name1, *name2;
293
294 gtk_tree_model_get(model, a, 0, &name1, -1);
295 gtk_tree_model_get(model, b, 0, &name2, -1);
296
297 retval = hb_string_utf8_compare(name1, name2);
298 /*
299 retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME);
300 if(!retval)
301 {
302 retval = hb_string_utf8_compare(entry1->name, entry2->name);
303 }
304 */
305 g_free(name2);
306 g_free(name1);
307
308 return retval;
309 }
310
311
312
313 static void
314 ui_cat_comboboxentry_test (GtkCellLayout *cell_layout,
315 GtkCellRenderer *cell,
316 GtkTreeModel *tree_model,
317 GtkTreeIter *iter,
318 gpointer data)
319 {
320 gchar *name;
321 gboolean subcat;
322 gint style;
323
324 //PANGO_STYLE_ITALIC
325
326 gtk_tree_model_get(tree_model, iter,
327 1, &name,
328 2, &subcat,
329 -1);
330
331 style = subcat == 0 ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
332
333 if( name == NULL )
334 name = _("(no category)"); //todo: not used
335
336 g_object_set(cell,
337 "style", style,
338 "text", name,
339 NULL);
340 }
341
342
343
344 static gboolean
345 ui_cat_comboboxentry_completion_func (GtkEntryCompletion *completion,
346 const gchar *key,
347 GtkTreeIter *iter,
348 gpointer user_data)
349 {
350 gchar *item = NULL;
351 gchar *normalized_string;
352 gchar *case_normalized_string;
353
354 gboolean ret = FALSE;
355
356 GtkTreeModel *model;
357
358 model = gtk_entry_completion_get_model (completion);
359
360 gtk_tree_model_get (model, iter,
361 0, &item,
362 -1);
363
364 if (item != NULL)
365 {
366 normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
367
368 if (normalized_string != NULL)
369 {
370 case_normalized_string = g_utf8_casefold (normalized_string, -1);
371
372 //g_print("match '%s' for '%s' ?\n", key, case_normalized_string);
373 //if (!strncmp (key, case_normalized_string, strlen (key)))
374 if (g_strstr_len (case_normalized_string, strlen (case_normalized_string), key ))
375 {
376 ret = TRUE;
377 // g_print(" ==> yes !\n");
378
379 }
380
381 g_free (case_normalized_string);
382 }
383 g_free (normalized_string);
384 }
385 g_free (item);
386
387 return ret;
388 }
389
390
391 /**
392 * ui_cat_comboboxentry_new:
393 *
394 * Create a new category comboboxentry
395 *
396 * Return value: the new widget
397 *
398 */
399 GtkWidget *
400 ui_cat_comboboxentry_new(GtkWidget *label)
401 {
402 GtkListStore *store;
403 GtkWidget *comboboxentry;
404 GtkEntryCompletion *completion;
405 GtkCellRenderer *renderer;
406
407 DB( g_print ("ui_cat_comboboxentry_new()\n") );
408
409
410 store = gtk_list_store_new (3,
411 G_TYPE_STRING, //fullname Car:Fuel
412 G_TYPE_STRING, //name Car or Fuel
413 G_TYPE_BOOLEAN //subcat = 1
414 );
415 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), ui_cat_comboboxentry_compare_func, NULL, NULL);
416
417 completion = gtk_entry_completion_new ();
418 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL(store));
419 g_object_set(completion, "text-column", 0, NULL);
420 gtk_entry_completion_set_match_func(completion, ui_cat_comboboxentry_completion_func, NULL, NULL);
421 gtk_entry_completion_set_minimum_key_length(completion, 2);
422
423 renderer = gtk_cell_renderer_text_new ();
424 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE);
425 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer, "text", 0, NULL);
426
427 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
428 renderer,
429 ui_cat_comboboxentry_test,
430 NULL, NULL);
431
432 // dothe same for combobox
433
434 comboboxentry = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(store));
435 gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(comboboxentry), 0);
436
437
438 gtk_cell_layout_clear(GTK_CELL_LAYOUT (comboboxentry));
439
440 renderer = gtk_cell_renderer_text_new ();
441 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comboboxentry), renderer, TRUE);
442 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comboboxentry), renderer, "text", 0, NULL);
443
444 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (comboboxentry),
445 renderer,
446 ui_cat_comboboxentry_test,
447 NULL, NULL);
448
449
450
451 gtk_entry_set_completion (GTK_ENTRY (gtk_bin_get_child(GTK_BIN (comboboxentry))), completion);
452
453 g_object_unref(store);
454
455 if(label)
456 gtk_label_set_mnemonic_widget (GTK_LABEL(label), comboboxentry);
457
458 gtk_widget_set_size_request(comboboxentry, HB_MINWIDTH_COMBO, -1);
459
460 return comboboxentry;
461 }
462
463 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
464
465 static void
466 ui_cat_listview_fixed_toggled (GtkCellRendererToggle *cell,
467 gchar *path_str,
468 gpointer data)
469 {
470 GtkTreeModel *model = (GtkTreeModel *)data;
471 GtkTreeIter iter;
472 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
473 gboolean fixed;
474
475 /* get toggled iter */
476 gtk_tree_model_get_iter (model, &iter, path);
477 gtk_tree_model_get (model, &iter, LST_DEFCAT_TOGGLE, &fixed, -1);
478
479 /* do something with the value */
480 fixed ^= 1;
481
482 /* set new value */
483 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, LST_DEFCAT_TOGGLE, fixed, -1);
484
485 /* clean up */
486 gtk_tree_path_free (path);
487 }
488
489 /*
490 **
491 ** The function should return:
492 ** a negative integer if the first value comes before the second,
493 ** 0 if they are equal,
494 ** or a positive integer if the first value comes after the second.
495 */
496 static gint
497 ui_cat_listview_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
498 {
499 gint retval = 0;
500 Category *entry1, *entry2;
501
502 gtk_tree_model_get(model, a, LST_DEFCAT_DATAS, &entry1, -1);
503 gtk_tree_model_get(model, b, LST_DEFCAT_DATAS, &entry2, -1);
504
505 retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME);
506 if(!retval)
507 {
508 retval = hb_string_utf8_compare(entry1->name, entry2->name);
509 }
510 return retval;
511 }
512
513
514 /*
515 ** draw some text from the stored data structure
516 */
517 static void
518 ui_cat_listview_text_cell_data_function (GtkTreeViewColumn *col,
519 GtkCellRenderer *renderer,
520 GtkTreeModel *model,
521 GtkTreeIter *iter,
522 gpointer user_data)
523 {
524 Category *entry;
525 gchar *name;
526 gchar *string;
527
528 gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &entry, -1);
529 if(entry->key == 0)
530 name = _("(no category)");
531 else
532 name = entry->name;
533
534 gchar type = (entry->flags & GF_INCOME) ? '+' : '-';
535
536 #if MYDEBUG
537 string = g_markup_printf_escaped ("%d > [%d] %s [%c] %d", entry->key, entry->parent, name, type, entry->flags );
538 #else
539 if(entry->key == 0)
540 string = g_strdup(name);
541 else
542 {
543 if( entry->parent == 0 )
544 string = g_markup_printf_escaped("%s [%c]", name, type);
545 else
546 string = g_markup_printf_escaped(" %c <i>%s</i>", type, name);
547 //string = g_strdup_printf(" - %s", name);
548 }
549 #endif
550
551 //g_object_set(renderer, "text", string, NULL);
552 g_object_set(renderer, "markup", string, NULL);
553
554 g_free(string);
555
556 }
557
558
559
560
561 void
562 ui_cat_listview_add(GtkTreeView *treeview, Category *item, GtkTreeIter *parent)
563 {
564 GtkTreeModel *model;
565 GtkTreeIter iter;
566 GtkTreePath *path;
567
568 DB( g_print ("ui_cat_listview_add()\n") );
569
570 if( item->name != NULL )
571 {
572 model = gtk_tree_view_get_model(treeview);
573
574 gtk_tree_store_append (GTK_TREE_STORE(model), &iter, parent);
575 gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
576 LST_DEFCAT_TOGGLE, FALSE,
577 LST_DEFCAT_DATAS, item,
578 LST_DEFCAT_NAME, item->name,
579 -1);
580
581 //select the added line
582
583 path = gtk_tree_model_get_path(model, &iter);
584 gtk_tree_view_expand_to_path (treeview, path);
585 gtk_tree_path_free(path);
586 gtk_tree_selection_select_iter (gtk_tree_view_get_selection(treeview), &iter);
587 }
588
589 }
590
591 Category *
592 ui_cat_listview_get_selected(GtkTreeView *treeview)
593 {
594 GtkTreeSelection *selection;
595 GtkTreeModel *model;
596 GtkTreeIter iter;
597
598 DB( g_print ("ui_cat_listview_get_selected()\n") );
599
600 selection = gtk_tree_view_get_selection(treeview);
601 if (gtk_tree_selection_get_selected(selection, &model, &iter))
602 {
603 Category *item;
604
605 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
606 if( item->key != 0 )
607 return item;
608 }
609 return NULL;
610 }
611
612 Category *
613 ui_cat_listview_get_selected_parent(GtkTreeView *treeview, GtkTreeIter *return_iter)
614 {
615 GtkTreeSelection *selection;
616 GtkTreeModel *model;
617 GtkTreeIter iter;
618 GtkTreePath *path;
619 Category *item;
620
621 DB( g_print ("ui_cat_listview_get_selected_parent()\n") );
622
623
624 selection = gtk_tree_view_get_selection(treeview);
625 if (gtk_tree_selection_get_selected(selection, &model, &iter))
626 {
627 path = gtk_tree_model_get_path(model, &iter);
628
629 DB( g_print ("path depth = %d\n", gtk_tree_path_get_depth(path)) );
630
631
632 if(gtk_tree_path_get_depth(path) > 1)
633 {
634 if( gtk_tree_path_up(path) )
635 {
636
637 DB( g_print ("up ok\n") );
638
639 if(gtk_tree_model_get_iter(model, &iter, path))
640 {
641
642 DB( g_print ("iter ok\n") );
643
644
645 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
646 if( item->key != 0 )
647 {
648 *return_iter = iter;
649 return item;
650 }
651 }
652 }
653 }
654 else
655 {
656
657 DB( g_print ("path <=1\n") );
658
659 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
660
661 if( item->key != 0 )
662 {
663 *return_iter = iter;
664 return item;
665 }
666
667
668 }
669 }
670 return NULL;
671 }
672
673 gboolean ui_cat_listview_remove (GtkTreeModel *model, guint32 key)
674 {
675 GtkTreeIter iter, child;
676 gboolean valid, cvalid;
677 Category *item;
678
679 DB( g_print("ui_cat_listview_remove() \n") );
680
681 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
682 while (valid)
683 {
684 gtk_tree_model_get (model, &iter, LST_DEFCAT_DATAS, &item, -1);
685
686 DB( g_print(" + item %p, %s\n", item, item->name) );
687
688 if(item->key == key || item->parent == key)
689 {
690 DB( g_print(" + removing cat %s\n", item->name) );
691 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
692 }
693
694 // iter children
695 cvalid = gtk_tree_model_iter_children (GTK_TREE_MODEL(model), &child, &iter);
696 while(cvalid)
697 {
698 gtk_tree_model_get(GTK_TREE_MODEL(model), &child, LST_DEFCAT_DATAS, &item, -1);
699 if(item->key == key || item->parent == key)
700 {
701 DB( g_print(" + removing subcat %s\n", item->name) );
702 gtk_tree_store_remove(GTK_TREE_STORE(model), &child);
703 }
704
705 cvalid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &child);
706 }
707 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
708 }
709
710 return TRUE;
711 }
712
713
714
715 void
716 ui_cat_listview_remove_selected(GtkTreeView *treeview)
717 {
718 GtkTreeSelection *selection;
719 GtkTreeModel *model;
720 GtkTreeIter iter;
721
722 DB( g_print("ui_cat_listview_remove_selected() \n") );
723
724 selection = gtk_tree_view_get_selection(treeview);
725 if (gtk_tree_selection_get_selected(selection, &model, &iter))
726 {
727 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
728 }
729 }
730
731
732 static gboolean
733 ui_cat_listview_get_top_level (GtkTreeModel *liststore, guint32 key, GtkTreeIter *return_iter)
734 {
735 GtkTreeIter iter;
736 gboolean valid;
737 Category *item;
738
739 DB( g_print("ui_cat_listview_get_top_level() \n") );
740
741 if( liststore != NULL )
742 {
743 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter);
744 while (valid)
745 {
746 gtk_tree_model_get (liststore, &iter, LST_DEFCAT_DATAS, &item, -1);
747
748 if(item->key == key)
749 {
750 *return_iter = iter;
751 return TRUE;
752 }
753
754 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter);
755 }
756 }
757
758 return FALSE;
759 }
760
761
762 static void ui_cat_listview_populate_cat_ghfunc(gpointer key, gpointer value, GtkTreeModel *model)
763 {
764 GtkTreeIter toplevel;
765 Category *item = value;
766
767 //DB( g_print("cat listview populate: %d %s\n", (guint32 *)key, item->name) );
768
769 if( item->parent == 0 )
770 {
771 gtk_tree_store_append (GTK_TREE_STORE(model), &toplevel, NULL);
772
773 gtk_tree_store_set (GTK_TREE_STORE(model), &toplevel,
774 LST_DEFCAT_TOGGLE , FALSE,
775 LST_DEFCAT_DATAS, item,
776 LST_DEFCAT_NAME, item->name,
777 -1);
778 }
779 }
780
781
782 static void ui_cat_listview_populate_subcat_ghfunc(gpointer key, gpointer value, GtkTreeModel *model)
783 {
784 GtkTreeIter toplevel, child;
785 Category *item = value;
786 gboolean ret;
787
788
789 if( item->parent != 0 )
790 {
791 ret = ui_cat_listview_get_top_level(model, item->parent, &toplevel);
792 if( ret == TRUE )
793 {
794 gtk_tree_store_append (GTK_TREE_STORE(model), &child, &toplevel);
795
796 gtk_tree_store_set (GTK_TREE_STORE(model), &child,
797 LST_DEFCAT_TOGGLE , FALSE,
798 LST_DEFCAT_DATAS, item,
799 LST_DEFCAT_NAME, item->name,
800 -1);
801
802 }
803 }
804
805 }
806
807
808 static void ui_cat_listview_sort_force(GtkTreeSortable *sortable, gpointer user_data)
809 {
810 gint sort_column_id;
811 GtkSortType order;
812
813 DB( g_print("ui_cat_listview_sort_force()\n") );
814
815 gtk_tree_sortable_get_sort_column_id(sortable, &sort_column_id, &order);
816 DB( g_print(" - id %d order %d\n", sort_column_id, order) );
817
818 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortable), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, order);
819 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortable), sort_column_id, order);
820 }
821
822
823
824
825 void ui_cat_listview_populate(GtkWidget *view)
826 {
827 GtkTreeModel *model;
828
829 DB( g_print("ui_cat_listview_populate() \n") );
830
831
832 model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
833
834 gtk_tree_store_clear (GTK_TREE_STORE(model));
835
836 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
837 gtk_tree_view_set_model(GTK_TREE_VIEW(view), NULL); /* Detach model from view */
838
839 /* we have to do this in 2 times to ensure toplevel (cat) will be added before childs */
840 /* populate cat 1st */
841 g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_cat_ghfunc, model);
842 g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_subcat_ghfunc, model);
843
844
845 gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); /* Re-attach model to view */
846 g_object_unref(model);
847
848 gtk_tree_view_expand_all (GTK_TREE_VIEW(view));
849
850 }
851
852
853 GtkWidget *
854 ui_cat_listview_new(gboolean withtoggle)
855 {
856 GtkTreeStore *store;
857 GtkWidget *treeview;
858 GtkCellRenderer *renderer;
859 GtkTreeViewColumn *column;
860
861 DB( g_print("ui_cat_listview_new() \n") );
862
863 /* create tree store */
864 store = gtk_tree_store_new(
865 NUM_LST_DEFCAT,
866 G_TYPE_BOOLEAN,
867 G_TYPE_POINTER,
868 G_TYPE_STRING
869 );
870
871 //treeview
872 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
873 g_object_unref(store);
874
875
876 // column 1: toggle
877 if( withtoggle == TRUE )
878 {
879 renderer = gtk_cell_renderer_toggle_new ();
880 column = gtk_tree_view_column_new_with_attributes ("Show", renderer, "active", LST_DEFCAT_TOGGLE, NULL);
881 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
882
883 g_signal_connect (G_OBJECT(renderer), "toggled",
884 G_CALLBACK (ui_cat_listview_fixed_toggled), store);
885
886 }
887
888 // column 1
889 column = gtk_tree_view_column_new();
890 renderer = gtk_cell_renderer_text_new ();
891 gtk_tree_view_column_pack_start(column, renderer, TRUE);
892 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_cat_listview_text_cell_data_function, GINT_TO_POINTER(LST_DEFCAT_NAME), NULL);
893 //gtk_tree_view_column_set_sort_column_id (column, LST_DEFACC_NAME);
894 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
895
896
897 // parameters
898 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE);
899
900 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_DATAS, ui_cat_listview_compare_func, NULL, NULL);
901 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), LST_DEFCAT_DATAS, GTK_SORT_ASCENDING);
902
903 //gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
904 //gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
905
906 return treeview;
907 }
908
909 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
910
911 //todo amiga/linux
912 //add exist function + check before add
913 //save
914 //load
915
916
917
918 /**
919 * ui_cat_manage_filter_text_handler
920 *
921 * filter to entry to avoid seizure of ':' char
922 *
923 */
924 static void ui_cat_manage_filter_text_handler (GtkEntry *entry,
925 const gchar *text,
926 gint length,
927 gint *position,
928 gpointer data)
929 {
930 GtkEditable *editable = GTK_EDITABLE(entry);
931 gint i, count=0, pos;
932 gchar *result = g_new0 (gchar, length+1);
933
934 for (i=0; i < length; i++)
935 {
936 if (text[i]==':')
937 continue;
938 result[count++] = text[i];
939 }
940
941
942 if (count > 0) {
943 g_signal_handlers_block_by_func (G_OBJECT (editable),
944 G_CALLBACK (ui_cat_manage_filter_text_handler),
945 data);
946 gtk_editable_insert_text (editable, result, count, &pos);
947 g_signal_handlers_unblock_by_func (G_OBJECT (editable),
948 G_CALLBACK (ui_cat_manage_filter_text_handler),
949 data);
950 }
951 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert_text");
952
953 g_free (result);
954 }
955
956
957
958
959 /**
960 * ui_cat_manage_dialog_load_csv:
961 *
962 */
963 static void
964 ui_cat_manage_dialog_load_csv( GtkWidget *widget, gpointer user_data)
965 {
966 struct ui_cat_manage_dialog_data *data;
967 gchar *filename = NULL;
968 gchar *error;
969
970 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
971
972 DB( g_print("(ui_cat_manage_dialog) load csv - data %p\n", data) );
973
974 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_OPEN, &filename, NULL) == TRUE )
975 {
976 DB( g_print(" + filename is %s\n", filename) );
977
978 if(!category_load_csv(filename, &error))
979 {
980 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
981 _("File format error"),
982 _("The csv file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.")
983 );
984 }
985
986 g_free( filename );
987 ui_cat_listview_populate(data->LV_cat);
988 }
989
990 }
991
992 /**
993 * ui_cat_manage_dialog_save_csv:
994 *
995 */
996 static void
997 ui_cat_manage_dialog_save_csv( GtkWidget *widget, gpointer user_data)
998 {
999 struct ui_cat_manage_dialog_data *data;
1000 gchar *filename = NULL;
1001 gchar *error;
1002
1003 DB( g_print("(defcategory) save csv\n") );
1004
1005 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1006
1007 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, NULL) == TRUE )
1008 {
1009 DB( g_print(" + filename is %s\n", filename) );
1010
1011 category_save_csv(filename, &error);
1012 g_free( filename );
1013 }
1014 }
1015
1016 /**
1017 * ui_cat_manage_dialog_add:
1018 *
1019 * add an empty new category/subcategory
1020 *
1021 */
1022 static void
1023 ui_cat_manage_dialog_add(GtkWidget *widget, gpointer user_data)
1024 {
1025 struct ui_cat_manage_dialog_data *data;
1026 gboolean subcat = GPOINTER_TO_INT(user_data);
1027 const gchar *name;
1028 //GtkTreeModel *model;
1029 GtkTreeIter parent_iter;
1030 GtkWidget *tmpwidget;
1031 Category *item, *paritem;
1032 gboolean type;
1033
1034 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1035 DB( g_print("\n(defcategory) add (data=%p) is subcat=%d\n", data, subcat) );
1036
1037 tmpwidget = (subcat == FALSE ? data->ST_name1 : data->ST_name2);
1038 name = gtk_entry_get_text(GTK_ENTRY(tmpwidget));
1039 //model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat));
1040
1041 /* ignore if item is empty */
1042 if (name && *name)
1043 {
1044 data->change++;
1045
1046 item = da_cat_malloc();
1047 item->name = g_strdup(name);
1048
1049 g_strstrip(item->name);
1050
1051 /* if cat use new id */
1052 if(subcat == FALSE)
1053 {
1054 type = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_type));
1055 if(type == TRUE)
1056 item->flags |= GF_INCOME;
1057
1058 if( da_cat_append(item) )
1059 {
1060 DB( g_print(" => add cat: %p %d, %s type=%d\n", item, subcat, item->name, type) );
1061 ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), item, NULL);
1062 }
1063 }
1064 /* if subcat use parent id & gf_income */
1065 else
1066 {
1067 paritem = ui_cat_listview_get_selected_parent(GTK_TREE_VIEW(data->LV_cat), &parent_iter);
1068 if(paritem)
1069 {
1070 DB( g_print(" => selitem parent: %d, %s\n", paritem->key, paritem->name) );
1071
1072 item->parent = paritem->key;
1073 item->flags |= (paritem->flags & GF_INCOME);
1074 item->flags |= GF_SUB;
1075
1076 if(da_cat_append(item))
1077 {
1078 DB( g_print(" => add subcat: %p %d, %s\n", item, subcat, item->name) );
1079 ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), item, &parent_iter);
1080 }
1081 }
1082 }
1083
1084 gtk_entry_set_text(GTK_ENTRY(tmpwidget),"");
1085 }
1086 }
1087
1088
1089 static void ui_cat_manage_dialog_modify_entry_cb(GtkEditable *editable, gpointer user_data)
1090 {
1091 GtkDialog *window = user_data;
1092 const gchar *buffer;
1093
1094 buffer = gtk_entry_get_text(GTK_ENTRY(editable));
1095 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, strlen(buffer) > 0 ? TRUE : FALSE);
1096 }
1097
1098
1099 /*
1100 **
1101 */
1102 static void
1103 ui_cat_manage_dialog_modify(GtkWidget *widget, gpointer user_data)
1104 {
1105 struct ui_cat_manage_dialog_data *data;
1106 GtkWidget *window, *content, *mainvbox, *w_name, *w_type = NULL;
1107 GtkTreeSelection *selection;
1108 GtkTreeModel *model;
1109 GtkTreeIter iter;
1110
1111 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1112 DB( g_print("\n(defcategory) modify\n") );
1113
1114 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat));
1115 //if true there is a selected node
1116 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1117 {
1118 Category *item;
1119
1120 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
1121
1122 window = gtk_dialog_new_with_buttons (_("Modify..."),
1123 GTK_WINDOW (data->window),
1124 0,
1125 GTK_STOCK_CANCEL,
1126 GTK_RESPONSE_REJECT,
1127 GTK_STOCK_OK,
1128 GTK_RESPONSE_ACCEPT,
1129 NULL);
1130
1131 content = gtk_dialog_get_content_area(GTK_DIALOG (window));
1132 mainvbox = gtk_vbox_new (FALSE, 0);
1133 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1134 gtk_container_set_border_width (GTK_CONTAINER (mainvbox), HB_MAINBOX_SPACING);
1135
1136 w_name = gtk_entry_new();
1137 gtk_box_pack_start (GTK_BOX (mainvbox), w_name, TRUE, TRUE, 0);
1138
1139 gtk_entry_set_text(GTK_ENTRY(w_name), item->name);
1140 gtk_widget_grab_focus (w_name);
1141
1142 gtk_entry_set_activates_default (GTK_ENTRY(w_name), TRUE);
1143
1144 if(!(item->flags & GF_SUB))
1145 {
1146 w_type = gtk_check_button_new_with_mnemonic(_("_Income"));
1147 gtk_box_pack_start (GTK_BOX (mainvbox), w_type, TRUE, TRUE, 0);
1148 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_type), item->flags & GF_INCOME ? TRUE : FALSE);
1149 }
1150
1151 gtk_widget_show_all(mainvbox);
1152
1153 g_signal_connect (G_OBJECT (w_name), "changed", G_CALLBACK (ui_cat_manage_dialog_modify_entry_cb), window);
1154
1155 gtk_dialog_set_default_response(GTK_DIALOG( window ), GTK_RESPONSE_ACCEPT);
1156
1157 //wait for the user
1158 gint result = gtk_dialog_run (GTK_DIALOG (window));
1159
1160 if(result == GTK_RESPONSE_ACCEPT)
1161 {
1162 const gchar *name;
1163
1164 // 1: manage renaming
1165 name = gtk_entry_get_text(GTK_ENTRY(w_name));
1166 // ignore if item is empty
1167 if (name && *name)
1168 {
1169 if( category_rename(item, name) )
1170 {
1171 data->change++;
1172 }
1173 else
1174 {
1175 Category *parent;
1176 gchar *fromname, *toname = NULL;
1177
1178 fromname = da_cat_get_fullname(item);
1179
1180 if( item->parent == 0)
1181 toname = g_strdup(name);
1182 else
1183 {
1184 parent = da_cat_get(item->parent);
1185 if( parent )
1186 {
1187 toname = g_strdup_printf("%s:%s", parent->name, name);
1188 }
1189 }
1190
1191
1192 ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR,
1193 _("Error"),
1194 _("Cannot rename this Category,\n"
1195 "from '%s' to '%s',\n"
1196 "this name already exists."),
1197 fromname,
1198 toname
1199 );
1200
1201 g_free(fromname);
1202 g_free(toname);
1203
1204 }
1205 }
1206
1207 // 2: manage flag change
1208 if(!(item->flags & GF_SUB))
1209 {
1210 gboolean isIncome;
1211
1212 isIncome = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_type));
1213 data->change += category_change_type(item, isIncome);
1214 }
1215
1216 ui_cat_listview_sort_force(GTK_TREE_SORTABLE(model), NULL);
1217 }
1218
1219 // cleanup and destroy
1220 gtk_widget_destroy (window);
1221 }
1222
1223 }
1224
1225
1226 static void ui_cat_manage_dialog_move_entry_cb(GtkComboBox *widget, gpointer user_data)
1227 {
1228 GtkDialog *window = user_data;
1229 gchar *buffer;
1230
1231 buffer = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (widget))));
1232 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, strlen(buffer) > 0 ? TRUE : FALSE);
1233 }
1234
1235
1236 /*
1237 **
1238 */
1239 static void ui_cat_manage_dialog_move(GtkWidget *widget, gpointer user_data)
1240 {
1241 struct ui_cat_manage_dialog_data *data;
1242 GtkWidget *window, *content, *mainvbox, *getwidget;
1243 GtkTreeSelection *selection;
1244 GtkTreeModel *model;
1245 GtkTreeIter iter;
1246
1247 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1248 DB( g_print("(defcategory) move\n") );
1249
1250 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat));
1251 //if true there is a selected node
1252 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1253 {
1254 Category *item;
1255
1256 gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1);
1257
1258 window = gtk_dialog_new_with_buttons (_("Move to..."),
1259 GTK_WINDOW (data->window),
1260 0,
1261 GTK_STOCK_CANCEL,
1262 GTK_RESPONSE_REJECT,
1263 GTK_STOCK_OK,
1264 GTK_RESPONSE_ACCEPT,
1265 NULL);
1266
1267 content = gtk_dialog_get_content_area(GTK_DIALOG (window));
1268 mainvbox = gtk_vbox_new (FALSE, 0);
1269 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1270 gtk_container_set_border_width (GTK_CONTAINER (mainvbox), HB_BOX_SPACING);
1271
1272 getwidget = ui_cat_comboboxentry_new(NULL);
1273 gtk_box_pack_start (GTK_BOX (mainvbox), getwidget, TRUE, TRUE, 0);
1274
1275 gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, FALSE);
1276
1277 gtk_widget_show_all(mainvbox);
1278
1279 g_signal_connect (G_OBJECT (getwidget), "changed", G_CALLBACK (ui_cat_manage_dialog_move_entry_cb), window);
1280
1281 ui_cat_comboboxentry_populate_except(GTK_COMBO_BOX(getwidget), GLOBALS->h_cat, item->key);
1282 gtk_widget_grab_focus (getwidget);
1283
1284 //wait for the user
1285 gint result = gtk_dialog_run (GTK_DIALOG (window));
1286
1287 if(result == GTK_RESPONSE_ACCEPT)
1288 {
1289 gboolean result;
1290 gchar *npn;
1291
1292 npn = ui_cat_comboboxentry_get_name(GTK_COMBO_BOX(getwidget)),
1293
1294 result = ui_dialog_msg_question(
1295 GTK_WINDOW(window),
1296 _("Move this category to another one ?"),
1297 _("This will replace '%s' by '%s',\n"
1298 "and then remove '%s'"),
1299 item->name,
1300 npn,
1301 item->name,
1302 NULL
1303 );
1304
1305 if( result == GTK_RESPONSE_YES )
1306 {
1307 Category *newcat, *parent;
1308 guint dstkey;
1309
1310 dstkey = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(getwidget));
1311 newcat = da_cat_get (dstkey);
1312
1313 DB( g_print(" moving to %d\n", dstkey) );
1314
1315 category_move(item->key, dstkey);
1316
1317 //keep the income with us
1318 parent = da_cat_get(item->parent);
1319 if(parent != NULL && (parent->flags & GF_INCOME))
1320 newcat->flags |= GF_INCOME;
1321
1322 // remove the old category
1323 da_cat_remove(item->key);
1324 ui_cat_listview_remove_selected(GTK_TREE_VIEW(data->LV_cat));
1325
1326 //add the new category into listview
1327 if(newcat)
1328 ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), newcat, NULL);
1329
1330 data->change++;
1331 }
1332 }
1333
1334 // cleanup and destroy
1335 gtk_widget_destroy (window);
1336 }
1337
1338 }
1339
1340
1341 /*
1342 ** remove the selected payee to our treeview and temp GList
1343 */
1344 static void ui_cat_manage_dialog_remove(GtkWidget *widget, gpointer user_data)
1345 {
1346 struct ui_cat_manage_dialog_data *data;
1347 Category *item;
1348 gint result;
1349 gboolean do_remove;
1350
1351 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1352 DB( g_print("\n(defcategory) remove (data=%x)\n", (guint)data) );
1353
1354 do_remove = TRUE;
1355 item = ui_cat_listview_get_selected(GTK_TREE_VIEW(data->LV_cat));
1356 if( item != NULL )
1357 {
1358 if( category_is_used(item->key) == TRUE )
1359 {
1360 result = ui_dialog_msg_question(
1361 GTK_WINDOW(data->window),
1362 _("Remove a category ?"),
1363 _("If you remove '%s', archive and transaction referencing this category\n"
1364 "will set place to 'no category'"),
1365 item->name,
1366 NULL
1367 );
1368
1369 if( result == GTK_RESPONSE_YES )
1370 {
1371 category_move(item->key, 0);
1372 }
1373 else if( result == GTK_RESPONSE_NO )
1374 {
1375 do_remove = FALSE;
1376 }
1377 }
1378
1379 if( do_remove )
1380 {
1381 ui_cat_listview_remove(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat)), item->key);
1382 da_cat_remove(item->key);
1383 data->change++;
1384 }
1385 }
1386
1387 }
1388
1389
1390 /**
1391 * ui_cat_manage_dialog_update:
1392 *
1393 */
1394 static void
1395 ui_cat_manage_dialog_update(GtkWidget *treeview, gpointer user_data)
1396 {
1397 struct ui_cat_manage_dialog_data *data;
1398 //gint count;
1399 gboolean selected, sensitive;
1400 GtkTreeSelection *selection;
1401 GtkTreeModel *model;
1402 GtkTreeIter iter;
1403 GtkTreePath *path;
1404 gchar *category;
1405 gboolean haschild = FALSE;
1406
1407 DB( g_print("ui_cat_manage_dialog_update()\n") );
1408
1409 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
1410 //window = gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW);
1411 //DB( g_print("(defpayee) widget=%08lx, window=%08lx, inst_data=%08lx\n", treeview, window, data) );
1412
1413 //if true there is a selected node
1414 selected = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)), &model, &iter);
1415
1416 DB( g_print(" selected = %d\n", selected) );
1417
1418 if(selected)
1419 {
1420 //path 0 active ?
1421 gtk_tree_model_get_iter_first(model, &iter);
1422 if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)), &iter))
1423 {
1424 DB( g_print(" 0 active = %d\n", 1) );
1425 selected = FALSE;
1426 }
1427 }
1428
1429 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1430
1431 //count = gtk_tree_selection_count_selected_rows(selection);
1432 //DB( g_print(" => select count=%d\n", count) );
1433
1434 category = NULL;
1435 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1436 {
1437 gchar *tree_path_str;
1438 Category *item;
1439
1440 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1441 LST_DEFCAT_DATAS, &item,
1442 -1);
1443
1444 haschild = gtk_tree_model_iter_has_child(GTK_TREE_MODEL(model), &iter);
1445 DB( g_print(" => has child=%d\n", haschild) );
1446
1447
1448 path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)), &iter);
1449 tree_path_str = gtk_tree_path_to_string(path);
1450 DB( g_print(" => select is=%s, depth=%d (id=%d, %s) flags=%d\n",
1451 tree_path_str,
1452 gtk_tree_path_get_depth(path),
1453 item->key,
1454 item->name,
1455 item->flags
1456 ) );
1457 g_free(tree_path_str);
1458
1459 //get parent if subcategory selectd
1460 DB( g_print(" => get parent for title\n") );
1461 if(gtk_tree_path_get_depth(path) != 1)
1462 gtk_tree_path_up(path);
1463
1464 if(gtk_tree_model_get_iter(model, &iter, path))
1465 {
1466 Category *tmpitem;
1467
1468 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1469 LST_DEFCAT_DATAS, &tmpitem,
1470 -1);
1471
1472 category = tmpitem->name;
1473
1474
1475 DB( g_print(" => parent is %s\n", category) );
1476
1477 }
1478
1479 gtk_tree_path_free(path);
1480
1481 }
1482
1483 gtk_label_set_text(GTK_LABEL(data->LA_category), category);
1484
1485 sensitive = (selected == TRUE) ? TRUE : FALSE;
1486 gtk_widget_set_sensitive(data->ST_name2, sensitive);
1487 gtk_widget_set_sensitive(data->BT_add2, sensitive);
1488 gtk_widget_set_sensitive(data->BT_mov, sensitive);
1489 gtk_widget_set_sensitive(data->BT_mod, sensitive);
1490
1491 //avoid removing top categories
1492 sensitive = (haschild == TRUE) ? FALSE : sensitive;
1493
1494 gtk_widget_set_sensitive(data->BT_rem, sensitive);
1495 }
1496
1497
1498 /*
1499 **
1500 */
1501 static void ui_cat_manage_dialog_selection(GtkTreeSelection *treeselection, gpointer user_data)
1502 {
1503 ui_cat_manage_dialog_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), NULL);
1504 }
1505
1506 static void ui_cat_manage_dialog_onRowActivated (GtkTreeView *treeview,
1507 GtkTreePath *path,
1508 GtkTreeViewColumn *col,
1509 gpointer user_data)
1510 {
1511 GtkTreeModel *model;
1512 GtkTreeIter iter;
1513
1514 DB( g_print("ui_cat_manage_dialog_onRowActivated()\n") );
1515
1516
1517 model = gtk_tree_view_get_model(treeview);
1518 gtk_tree_model_get_iter_first(model, &iter);
1519 if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), &iter) == FALSE)
1520 {
1521 ui_cat_manage_dialog_modify(GTK_WIDGET(treeview), NULL);
1522 }
1523 }
1524
1525
1526
1527
1528 /*
1529 **
1530 */
1531 static gboolean ui_cat_manage_dialog_cleanup(struct ui_cat_manage_dialog_data *data, gint result)
1532 {
1533 gboolean doupdate = FALSE;
1534
1535 DB( g_print("(defcategory) cleanup\n") );
1536
1537 if(result == GTK_RESPONSE_ACCEPT)
1538 {
1539
1540 //do_application_specific_something ();
1541 DB( g_print(" accept\n") );
1542
1543
1544 GLOBALS->changes_count += data->change;
1545 }
1546
1547 DB( g_print(" free tmp_list\n") );
1548
1549 //da_category_destroy(data->tmp_list);
1550
1551 return doupdate;
1552 }
1553
1554 /*
1555 **
1556 */
1557 static void ui_cat_manage_dialog_setup(struct ui_cat_manage_dialog_data *data)
1558 {
1559 DB( g_print("(defcategory) setup\n") );
1560
1561 //init GList
1562 data->tmp_list = NULL; //data->tmp_list = hb-glist_clone_list(GLOBALS->cat_list, sizeof(struct _Group));
1563 data->change = 0;
1564
1565 //debug
1566 //da_cat_debug_list();
1567
1568
1569 ui_cat_listview_populate(data->LV_cat);
1570 gtk_tree_view_expand_all (GTK_TREE_VIEW(data->LV_cat));
1571
1572 }
1573
1574 // the window creation
1575 GtkWidget *ui_cat_manage_dialog (void)
1576 {
1577 struct ui_cat_manage_dialog_data data;
1578 GtkWidget *window, *content, *mainvbox, *table, *hbox, *label, *scrollwin, *vbox, *separator, *treeview;
1579 gint row;
1580
1581 window = gtk_dialog_new_with_buttons (_("Manage Categories"),
1582 GTK_WINDOW(GLOBALS->mainwindow),
1583 0,
1584 GTK_STOCK_CLOSE,
1585 GTK_RESPONSE_ACCEPT,
1586 NULL);
1587
1588 data.window = window;
1589
1590 //set the window icon
1591 //homebank_window_set_icon_from_file(GTK_WINDOW (window), "category.svg");
1592 gtk_window_set_icon_name(GTK_WINDOW (window), HB_STOCK_CATEGORY);
1593
1594 //store our window private data
1595 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)&data);
1596 DB( g_print("(defcategory) window=%x, inst_data=%x\n", (guint)window, (guint)&data) );
1597
1598 g_signal_connect (window, "destroy",
1599 G_CALLBACK (gtk_widget_destroyed), &window);
1600
1601 //window contents
1602 content = gtk_dialog_get_content_area(GTK_DIALOG (window));
1603 mainvbox = gtk_vbox_new (FALSE, 0);
1604 gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0);
1605 gtk_container_set_border_width (GTK_CONTAINER(mainvbox), HB_MAINBOX_SPACING);
1606
1607 //our table
1608 table = gtk_table_new (3, 2, FALSE);
1609 gtk_table_set_row_spacings (GTK_TABLE (table), HB_TABROW_SPACING);
1610 gtk_table_set_col_spacings (GTK_TABLE (table), HB_TABCOL_SPACING);
1611 gtk_box_pack_start (GTK_BOX (mainvbox), table, TRUE, TRUE, 0);
1612
1613 // category item + add button
1614 row = 0;
1615 hbox = gtk_hbox_new (FALSE, HB_BOX_SPACING);
1616 gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, row, row+1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1617 data.ST_name1 = gtk_entry_new ();
1618 gtk_box_pack_start (GTK_BOX (hbox), data.ST_name1, TRUE, TRUE, 0);
1619 data.CM_type = gtk_check_button_new_with_mnemonic(_("I_ncome"));
1620 gtk_box_pack_start (GTK_BOX (hbox), data.CM_type, FALSE, FALSE, 0);
1621
1622 data.BT_add1 = gtk_button_new_from_stock(GTK_STOCK_ADD);
1623 gtk_table_attach (GTK_TABLE (table), data.BT_add1, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1624
1625 // subcategory + add button
1626 row++;
1627 hbox = gtk_hbox_new (FALSE, HB_BOX_SPACING);
1628 gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, row, row+1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1629 data.LA_category = gtk_label_new(NULL);
1630 gtk_box_pack_start (GTK_BOX (hbox), data.LA_category, FALSE, FALSE, 0);
1631 label = gtk_label_new(":");
1632 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1633 data.ST_name2 = gtk_entry_new ();
1634 gtk_box_pack_start (GTK_BOX (hbox), data.ST_name2, TRUE, TRUE, 0);
1635 data.BT_add2 = gtk_button_new_from_stock(GTK_STOCK_ADD);
1636 gtk_table_attach (GTK_TABLE (table), data.BT_add2, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1637
1638
1639
1640
1641 //list
1642 row++;
1643 scrollwin = gtk_scrolled_window_new(NULL,NULL);
1644 gtk_table_attach (GTK_TABLE (table), scrollwin, 0, 1, row, row+1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0);
1645
1646 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN);
1647 //gtk_container_set_border_width (GTK_CONTAINER(scrollwin), 5);
1648 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1649 treeview = (GtkWidget *)ui_cat_listview_new(FALSE);
1650 gtk_widget_set_size_request(treeview, HB_MINWIDTH_LIST, -1);
1651 data.LV_cat = treeview;
1652 gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
1653
1654 vbox = gtk_vbox_new (FALSE, HB_BOX_SPACING);
1655 gtk_table_attach (GTK_TABLE (table), vbox, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0);
1656
1657 /*
1658 widget = gtk_check_button_new_with_mnemonic("Income type");
1659 data.CM_type = widget;
1660 gtk_box_pack_start (GTK_BOX (vbox), data.CM_type, FALSE, FALSE, 0);
1661 */
1662
1663 data.BT_rem = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
1664 gtk_box_pack_start (GTK_BOX (vbox), data.BT_rem, FALSE, FALSE, 0);
1665
1666 data.BT_mod = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1667 //data.BT_mod = gtk_button_new_with_mnemonic(_("_Modify"));
1668 gtk_box_pack_start (GTK_BOX (vbox), data.BT_mod, FALSE, FALSE, 0);
1669
1670 data.BT_mov = gtk_button_new_with_mnemonic(_("_Move"));
1671 gtk_box_pack_start (GTK_BOX (vbox), data.BT_mov, FALSE, FALSE, 0);
1672
1673 separator = gtk_hseparator_new();
1674 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, HB_BOX_SPACING);
1675
1676
1677 data.BT_import = gtk_button_new_with_mnemonic(_("_Import"));
1678 //data.BT_import = gtk_button_new_from_stock(GTK_STOCK_OPEN);
1679 gtk_box_pack_start (GTK_BOX (vbox), data.BT_import, FALSE, FALSE, 0);
1680
1681 data.BT_export = gtk_button_new_with_mnemonic(_("E_xport"));
1682 //data.BT_export = gtk_button_new_from_stock(GTK_STOCK_SAVE);
1683 gtk_box_pack_start (GTK_BOX (vbox), data.BT_export, FALSE, FALSE, 0);
1684
1685 //connect all our signals
1686 g_signal_connect (G_OBJECT (data.ST_name1), "activate", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(FALSE));
1687 g_signal_connect (G_OBJECT (data.ST_name2), "activate", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(TRUE));
1688
1689 g_signal_connect(G_OBJECT(data.ST_name1), "insert_text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL);
1690 g_signal_connect(G_OBJECT(data.ST_name2), "insert_text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL);
1691
1692
1693 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_cat)), "changed", G_CALLBACK (ui_cat_manage_dialog_selection), NULL);
1694 g_signal_connect (GTK_TREE_VIEW(data.LV_cat), "row-activated", G_CALLBACK (ui_cat_manage_dialog_onRowActivated), NULL);
1695
1696 g_signal_connect (G_OBJECT (data.BT_add1), "clicked", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(FALSE));
1697 g_signal_connect (G_OBJECT (data.BT_add2), "clicked", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(TRUE));
1698 g_signal_connect (G_OBJECT (data.BT_mod), "clicked", G_CALLBACK (ui_cat_manage_dialog_modify), NULL);
1699 g_signal_connect (G_OBJECT (data.BT_mov), "clicked", G_CALLBACK (ui_cat_manage_dialog_move), NULL);
1700 g_signal_connect (G_OBJECT (data.BT_rem), "clicked", G_CALLBACK (ui_cat_manage_dialog_remove), NULL);
1701
1702 g_signal_connect (G_OBJECT (data.BT_import), "clicked", G_CALLBACK (ui_cat_manage_dialog_load_csv), NULL);
1703 g_signal_connect (G_OBJECT (data.BT_export), "clicked", G_CALLBACK (ui_cat_manage_dialog_save_csv), NULL);
1704
1705 //setup, init and show window
1706 ui_cat_manage_dialog_setup(&data);
1707 ui_cat_manage_dialog_update(data.LV_cat, NULL);
1708
1709 gtk_window_resize(GTK_WINDOW(window), 200, 320);
1710
1711
1712 gtk_widget_show_all (window);
1713
1714 //wait for the user
1715 gint result = gtk_dialog_run (GTK_DIALOG (window));
1716
1717 switch (result)
1718 {
1719 case GTK_RESPONSE_ACCEPT:
1720 //do_application_specific_something ();
1721 break;
1722 default:
1723 //do_nothing_since_dialog_was_cancelled ();
1724 break;
1725 }
1726
1727 // cleanup and destroy
1728 ui_cat_manage_dialog_cleanup(&data, result);
1729 gtk_widget_destroy (window);
1730
1731 return NULL;
1732 }
1733
1734
1735
This page took 0.104162 seconds and 4 git commands to generate.