add gitignore
[chaz/homebank] / src / ui-budget.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
21 #include "homebank.h"
22
23 #include "ui-category.h"
24 #include "ui-budget.h"
25
26
27 /****************************************************************************/
28 /* Debug macros */
29 /****************************************************************************/
30 #define MYDEBUG 0
31
32 #if MYDEBUG
33 #define DB(x) (x);
34 #else
35 #define DB(x);
36 #endif
37
38 /* our global datas */
39 extern struct HomeBank *GLOBALS;
40
41
42
43
44
45 gchar *months[] = {
46 "Jan",
47 "Feb",
48 "Mar",
49 "Apr",
50 "May",
51 "Jun",
52 "Jul",
53 "Aug",
54 "Sep",
55 "Oct",
56 "Nov",
57 "Dec"
58 };
59
60 static gchar *ui_bud_manage_getcsvbudgetstr(Category *item);
61 static void ui_bud_manage_update(GtkWidget *treeview, gpointer user_data);
62 static void ui_bud_manage_set(GtkWidget *widget, gpointer user_data);
63 static void ui_bud_manage_getlast(struct ui_bud_manage_data *data);
64 static void ui_bud_manage_selection_change(GtkWidget *treeview, gpointer user_data);
65 static void ui_bud_manage_toggle(GtkRadioButton *radiobutton, gpointer user_data);
66 static void ui_bud_manage_selection(GtkTreeSelection *treeselection, gpointer user_data);
67
68
69 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
70
71 /*
72 **
73 ** The function should return:
74 ** a negative integer if the first value comes before the second,
75 ** 0 if they are equal,
76 ** or a positive integer if the first value comes after the second.
77 */
78 static gint ui_bud_listview_compare_funct (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
79 {
80 gint retval = 0;
81 Category *entry1, *entry2;
82
83 gtk_tree_model_get(model, a, LST_DEFCAT_DATAS, &entry1, -1);
84 gtk_tree_model_get(model, b, LST_DEFCAT_DATAS, &entry2, -1);
85
86 retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME);
87 if(!retval)
88 {
89 retval = hb_string_utf8_compare(entry1->name, entry2->name);
90 }
91
92 return retval;
93 }
94
95 /*
96 ** draw some text from the stored data structure
97 */
98 static void ui_bud_listview_cell_data_function_text (GtkTreeViewColumn *col,
99 GtkCellRenderer *renderer,
100 GtkTreeModel *model,
101 GtkTreeIter *iter,
102 gpointer user_data)
103 {
104 Category *entry;
105 gchar *name;
106 gchar *string;
107 gchar type;
108
109 gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &entry, -1);
110
111 if(entry->key == 0)
112 name = g_strdup(_("(no category)"));
113 else
114 name = entry->name;
115
116 type = (entry->flags & GF_INCOME) ? '+' : '-';
117
118 #if MYDEBUG
119 string = g_markup_printf_escaped("%s ::(f=%d, %c)", name, entry->flags, type );
120 #else
121 if(entry->key == 0)
122 string = g_strdup(name);
123 else
124 {
125 if(entry->flags & GF_BUDGET)
126 {
127 if( entry->parent == 0 )
128 string = g_markup_printf_escaped("<b>%s</b> [%c]", name, type);
129 else
130 string = g_markup_printf_escaped(" %c <b><i>%s</i></b>", type, name);
131 }
132 else
133 {
134 if( entry->parent == 0 )
135 string = g_markup_printf_escaped("%s [%c]", name, type);
136 else
137 string = g_markup_printf_escaped(" %c <i>%s</i>", type, name);
138 }
139 }
140 #endif
141
142 g_object_set(renderer, "markup", string, NULL);
143
144 g_free(string);
145 }
146
147 /*
148 **
149 */
150 static GtkWidget *ui_bud_listview_new(void)
151 {
152 GtkTreeStore *store;
153 GtkWidget *view;
154 GtkCellRenderer *renderer;
155 GtkTreeViewColumn *column;
156
157 //store
158 store = gtk_tree_store_new (
159 3,
160 //NUM_LST_DEFCAT,
161 G_TYPE_BOOLEAN,
162 G_TYPE_POINTER,
163 G_TYPE_UINT
164 );
165
166 //sortable
167 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_DATAS, ui_bud_listview_compare_funct, NULL, NULL);
168 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), LST_DEFCAT_DATAS, GTK_SORT_ASCENDING);
169
170
171 //treeview
172 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
173 g_object_unref(store);
174
175 /* column 1 */
176 column = gtk_tree_view_column_new();
177 renderer = gtk_cell_renderer_text_new ();
178 gtk_tree_view_column_pack_start(column, renderer, TRUE);
179 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_bud_listview_cell_data_function_text, GINT_TO_POINTER(1), NULL);
180 //gtk_tree_view_column_set_sort_column_id (column, LST_DEFACC_NAME);
181 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
182
183 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE);
184 //gtk_tree_view_set_reorderable (GTK_TREE_VIEW(view), TRUE);
185
186 return(view);
187 }
188
189
190
191 /*
192 ** index 0 is all month, then 1 -> 12 are months
193 */
194 static gchar *ui_bud_manage_getcsvbudgetstr(Category *item)
195 {
196 gchar *retval = NULL;
197 char buf[G_ASCII_DTOSTR_BUF_SIZE];
198
199 //DB( g_print(" get budgetstr for '%s'\n", item->name) );
200
201 if( !(item->flags & GF_CUSTOM) )
202 {
203 if( item->budget[0] )
204 {
205 g_ascii_dtostr (buf, sizeof (buf), item->budget[0]);
206 retval = g_strdup(buf);
207
208 //DB( g_print(" => %d: %s\n", 0, retval) );
209 }
210 }
211 else
212 {
213 gint i;
214
215 for(i=1;i<=12;i++)
216 {
217 //if( item->budget[i] )
218 //{
219 gchar *tmp = retval;
220
221 g_ascii_dtostr (buf, sizeof (buf), item->budget[i]);
222
223 if(retval != NULL)
224 {
225 retval = g_strconcat(retval, ";", buf, NULL);
226 g_free(tmp);
227 }
228 else
229 retval = g_strdup(buf);
230
231 //DB( g_print(" => %d: %s\n", i, retval) );
232
233 //}
234 }
235 }
236
237 return retval;
238 }
239
240
241 static gint ui_bud_manage_category_exists (GtkTreeModel *model, gchar *level, gchar *type, gchar *name, GtkTreeIter *return_iter)
242 {
243 GtkTreeIter iter, child;
244 gboolean valid;
245 Category *entry;
246 gint pos = 0;
247
248 if(model == NULL)
249 return 0;
250
251 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
252
253 while (valid)
254 {
255 gtk_tree_model_get (model, &iter, LST_DEFCAT_DATAS, &entry, -1);
256
257 if(*level == '1')
258 {
259 if(entry->name && g_ascii_strcasecmp(name, entry->name) == 0)
260 {
261 *return_iter = iter;
262 return pos;
263 }
264 }
265 else
266 {
267 if(*level == '2')
268 {
269 gint n_child = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(model), &iter);
270 gtk_tree_model_iter_children (GTK_TREE_MODEL(model), &child, &iter);
271 while(n_child > 0)
272 {
273
274 gtk_tree_model_get(GTK_TREE_MODEL(model), &child,
275 LST_DEFCAT_DATAS, &entry,
276 -1);
277
278 if(entry->name && g_ascii_strcasecmp(name, entry->name) == 0)
279 {
280 *return_iter = child;
281 return pos;
282 }
283
284 n_child--;
285 gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &child);
286 pos++;
287 }
288 }
289 }
290 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
291 pos++;
292 }
293
294 return 0;
295 }
296
297
298 static void ui_bud_manage_load_csv( GtkWidget *widget, gpointer user_data)
299 {
300 struct ui_bud_manage_data *data = user_data;
301 gchar *filename = NULL;
302 GIOChannel *io;
303 const gchar *encoding;
304
305
306 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
307
308
309 DB( g_print("(ui_bud_manage) load csv - data %p\n", data) );
310
311 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_OPEN, &filename, NULL) == TRUE )
312 {
313 DB( g_print(" + filename is %s\n", filename) );
314
315 encoding = homebank_file_getencoding(filename);
316
317 io = g_io_channel_new_file(filename, "r", NULL);
318 if(io != NULL)
319 {
320 GtkTreeModel *model;
321 GtkTreeIter iter;
322 gboolean error = FALSE;
323 gchar *tmpstr;
324 gint io_stat;
325
326 DB( g_print(" -> encoding should be %s\n", encoding) );
327 if( encoding != NULL )
328 {
329 g_io_channel_set_encoding(io, encoding, NULL);
330 }
331
332 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat));
333
334
335 for(;;)
336 {
337 io_stat = g_io_channel_read_line(io, &tmpstr, NULL, NULL, NULL);
338 if( io_stat == G_IO_STATUS_EOF)
339 break;
340 if( io_stat == G_IO_STATUS_NORMAL)
341 {
342 if( tmpstr != NULL)
343 {
344 gchar **str_array;
345
346 hb_string_strip_crlf(tmpstr);
347
348 str_array = g_strsplit (tmpstr, ";", 15);
349 // type; sign; name
350
351 if( (g_strv_length (str_array) < 4 || *str_array[1] != '*') && (g_strv_length (str_array) < 15))
352 {
353 error = TRUE;
354 break;
355 }
356
357 DB( g_print(" csv read '%s : %s : %s ...'\n", str_array[0], str_array[1], str_array[2]) );
358
359 gint pos = ui_bud_manage_category_exists(model, str_array[0], str_array[1], str_array[2], &iter);
360
361 DB( g_print(" pos=%d\n", pos) );
362
363 if( pos != 0 )
364 {
365 gboolean budget;
366 Category *tmpitem;
367 gint i;
368
369 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
370 LST_DEFCAT_DATAS, &tmpitem,
371 -1);
372
373 DB( g_print(" found cat, updating '%s'\n", tmpitem->name) );
374
375 data->change++;
376
377 tmpitem->flags &= ~(GF_CUSTOM); //remove flag
378 if( *str_array[1] == '*' )
379 {
380 tmpitem->budget[0] = g_ascii_strtod(str_array[3], NULL);
381
382 DB( g_print(" monthly '%.2f'\n", tmpitem->budget[0]) );
383 }
384 else
385 {
386 tmpitem->flags |= (GF_CUSTOM);
387
388 for(i=1;i<=12;i++)
389 {
390 tmpitem->budget[i] = g_ascii_strtod(str_array[2+i], NULL);
391 DB( g_print(" month %d '%.2f'\n", i, tmpitem->budget[i]) );
392 }
393 }
394
395 // if any value,set the flag to visual indicator
396 budget = FALSE;
397 tmpitem->flags &= ~(GF_BUDGET); //remove flag
398 for(i=0;i<=12;i++)
399 {
400 if(tmpitem->budget[i])
401 {
402 budget = TRUE;
403 break;
404 }
405 }
406
407 if(budget == TRUE)
408 tmpitem->flags |= GF_BUDGET;
409 }
410
411 g_strfreev (str_array);
412 }
413 g_free(tmpstr);
414 }
415
416 }
417
418 //update the treeview
419 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)));
420
421
422 g_io_channel_unref (io);
423
424 if( error == TRUE )
425 {
426 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
427 _("File format error"),
428 _("The csv file must contains the exact numbers of column,\nseparated by a semi-colon, read the help for more details.")
429 );
430 }
431
432 }
433
434 g_free( filename );
435
436 }
437 }
438
439 /*
440 **
441 */
442 static void ui_bud_manage_save_csv( GtkWidget *widget, gpointer user_data)
443 {
444 struct ui_bud_manage_data *data = user_data;
445 gchar *filename = NULL;
446 GtkTreeModel *model;
447 GtkTreeIter iter, child;
448 gboolean valid;
449 GIOChannel *io;
450
451 DB( g_print("(ui_bud_manage) save csv\n") );
452
453 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
454
455 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, NULL) == TRUE )
456 {
457
458 DB( g_print(" + filename is %s\n", filename) );
459
460 io = g_io_channel_new_file(filename, "w", NULL);
461 if(io != NULL)
462 {
463
464 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat));
465
466 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
467
468 while (valid)
469 {
470 gchar *outstr, *outvalstr;
471 Category *category;
472 gchar type;
473
474 gtk_tree_model_get (GTK_TREE_MODEL(model), &iter, LST_DEFCAT_DATAS, &category, -1);
475
476 if( category->name != NULL )
477 {
478
479 //level 1: category
480 if( category->flags & GF_BUDGET )
481 {
482 type = (category->flags & GF_CUSTOM) ? ' ' : '*';
483
484 outvalstr = ui_bud_manage_getcsvbudgetstr(category);
485 outstr = g_strdup_printf("1;%c;%s;%s\n", type, category->name, outvalstr);
486 DB( g_print("%s", outstr) );
487 g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
488 g_free(outstr);
489 g_free(outvalstr);
490 }
491
492
493 //level 2: subcategory
494 gint n_child = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(model), &iter);
495 gtk_tree_model_iter_children (GTK_TREE_MODEL(model), &child, &iter);
496 while(n_child > 0)
497 {
498 gtk_tree_model_get(GTK_TREE_MODEL(model), &child, LST_DEFCAT_DATAS, &category, -1);
499
500 type = (category->flags & GF_CUSTOM) ? ' ' : '*';
501
502 outvalstr = ui_bud_manage_getcsvbudgetstr(category);
503 if( outvalstr )
504 {
505 outstr = g_strdup_printf("2;%c;%s;%s\n", type, category->name, outvalstr);
506 DB( g_print("%s", outstr) );
507 g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
508 g_free(outstr);
509 }
510 g_free(outvalstr);
511
512 n_child--;
513 gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &child);
514 }
515 }
516
517 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
518 }
519
520 g_io_channel_unref (io);
521 }
522
523 g_free( filename );
524
525 }
526
527 }
528
529
530
531
532
533
534 /*
535 **
536 */
537 static void ui_bud_manage_update(GtkWidget *treeview, gpointer user_data)
538 {
539 struct ui_bud_manage_data *data;
540 gboolean name, custom, sensitive;
541 gint i;
542
543 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
544
545 DB( g_print("\n(ui_bud_manage) update %x\n", (gint)data) );
546
547
548 name = FALSE;
549 if(data->cat != NULL)
550 {
551 name = data->cat->name == NULL ? FALSE : TRUE;
552 }
553
554 sensitive = name;
555 gtk_widget_set_sensitive(data->CM_type[0], sensitive);
556 gtk_widget_set_sensitive(data->CM_type[1], sensitive);
557
558 gtk_widget_set_sensitive(data->BT_clear, sensitive);
559
560 #if MYDEBUG == 1
561 gint toto = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_type[0]));
562 DB( g_print(" monthly = %d\n", toto) );
563 #endif
564
565 custom = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_type[1]));
566 DB( g_print(" custom = %d\n\n", custom) );
567
568 sensitive = name == FALSE ? FALSE : custom == TRUE ? FALSE: TRUE;
569 gtk_widget_set_sensitive(data->spinner[0], sensitive);
570
571 sensitive = name == FALSE ? FALSE : custom;
572 for(i=0;i<12;i++)
573 {
574 gtk_widget_set_sensitive(data->spinner[i+1], sensitive);
575 }
576
577 }
578
579 /*
580 **
581 */
582 static void ui_bud_manage_clear(GtkWidget *widget, gpointer user_data)
583 {
584 struct ui_bud_manage_data *data;
585 gint i;
586
587 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
588
589 DB( g_print("(ui_bud_manage) clear\n") );
590
591 //g_signal_handler_block(data->CM_type[0], data->handler_id[HID_CUSTOM]);
592 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_type[0]), TRUE);
593 //g_signal_handler_unblock(data->CM_type[0], data->handler_id[HID_CUSTOM]);
594
595 for(i=0;i<=12;i++)
596 {
597 //g_signal_handler_block(data->spinner[i], data->spinner_hid[i]);
598
599 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->spinner[i]), 0);
600 data->cat->budget[i] = 0;
601
602 //g_signal_handler_unblock(data->spinner[i], data->spinner_hid[i]);
603 }
604
605 data->cat->flags &= ~(GF_BUDGET); //remove flag
606
607 gtk_widget_queue_draw (data->LV_cat);
608
609 }
610
611
612 /*
613 **
614 */
615 static void ui_bud_manage_set(GtkWidget *widget, gpointer user_data)
616 {
617 struct ui_bud_manage_data *data;
618 gint active;
619 gint i;
620
621 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
622
623 DB( g_print("(ui_bud_manage) set\n") );
624
625 active = data->cat->flags & GF_CUSTOM ? 1 : 0;
626 //data->custom = active;
627
628 //DB( g_print(" set custom to %d\n", data->custom) );
629
630 g_signal_handler_block(data->CM_type[0], data->handler_id[HID_CUSTOM]);
631 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_type[active]), TRUE);
632 g_signal_handler_unblock(data->CM_type[0], data->handler_id[HID_CUSTOM]);
633
634 for(i=0;i<=12;i++)
635 {
636 //g_signal_handler_block(data->spinner[i], data->spinner_hid[i]);
637
638 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->spinner[i]), data->cat->budget[i]);
639 //DB( g_print(" %.2f\n", data->cat->budget[i]) );
640
641 //g_signal_handler_unblock(data->spinner[i], data->spinner_hid[i]);
642 }
643
644 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_force), (data->cat->flags & GF_FORCED) ? 1 : 0);
645
646 }
647
648 /*
649 **
650 */
651 static void ui_bud_manage_getlast(struct ui_bud_manage_data *data)
652 {
653 gboolean budget, change;
654 gint i;
655 Category *item;
656 gdouble oldvalue;
657 gint active;
658
659 item = data->lastcatitem;
660
661 DB( g_print("****\n(ui_bud_manage) getlast for '%s'\n", item->name ) );
662
663 if( item != NULL )
664 {
665 gushort old_flags = item->flags;
666
667 item->flags &= ~(GF_CUSTOM);
668 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_type[0])) == FALSE)
669 item->flags |= GF_CUSTOM;
670
671 DB( g_print(" custom flag=%d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_type[1]))) );
672
673 // if any value,set the flag to visual indicator
674 budget = FALSE;
675 change = FALSE;
676 item->flags &= ~(GF_BUDGET); //remove flag
677 for(i=0;i<=12;i++)
678 {
679 gtk_spin_button_update(GTK_SPIN_BUTTON(data->spinner[i]));
680 oldvalue = item->budget[i];
681
682 item->budget[i] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->spinner[i]));
683
684 if( oldvalue != item->budget[i])
685 change = TRUE;
686
687 DB( g_print(" set value %d to %.2f\n", i, item->budget[i]) );
688 if(item->budget[i])
689 {
690 budget = TRUE;
691 }
692 }
693
694 item->flags &= ~(GF_FORCED); //remove flag
695 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_force));
696 if(active == 1)
697 item->flags |= GF_FORCED;
698
699 if(budget == TRUE || active == 1)
700 item->flags |= GF_BUDGET;
701
702 // compute chnages
703 if( (old_flags != item->flags) || change )
704 data->change++;
705
706 gtk_widget_queue_draw (data->LV_cat);
707
708 }
709
710 }
711
712
713
714
715 /*
716 **
717 */
718 static void ui_bud_manage_selection_change(GtkWidget *treeview, gpointer user_data)
719 {
720 struct ui_bud_manage_data *data;
721 GtkTreeModel *model;
722 GtkTreeIter iter;
723
724 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
725
726 DB( g_print("(ui_bud_manage) changed\n") );
727
728 data->cat = NULL;
729
730 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)), &model, &iter))
731 {
732 Category *item;
733
734 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
735 LST_DEFCAT_DATAS, &item,
736 -1);
737
738 DB( g_print(" selected %s\n", item->name) );
739
740 if(data->lastcatitem != NULL && item != data->lastcatitem)
741 {
742 DB( g_print(" -> should do a get for last selected (%s)\n", data->lastcatitem->name) );
743 ui_bud_manage_getlast(data);
744 }
745
746
747 data->cat = item;
748 data->lastcatitem = item;
749
750 ui_bud_manage_set(treeview, NULL);
751 }
752 else
753 {
754 data->lastcatitem = NULL;
755 }
756
757 ui_bud_manage_update(treeview, NULL);
758
759 }
760
761 static void ui_bud_manage_toggle(GtkRadioButton *radiobutton, gpointer user_data)
762 {
763 //struct ui_bud_manage_data *data;
764
765 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(radiobutton), GTK_TYPE_WINDOW)), "inst_data");
766
767 DB( g_print("(ui_bud_manage) toggle\n") );
768
769 //ui_bud_manage_get(GTK_WIDGET(radiobutton), GINT_TO_POINTER(FIELD_TYPE));
770
771 //data->custom ^= 1;
772 ui_bud_manage_update(GTK_WIDGET(radiobutton), NULL);
773 }
774
775 /*
776 **
777 */
778 void ui_bud_manage_selection(GtkTreeSelection *treeselection, gpointer user_data)
779 {
780 ui_bud_manage_selection_change(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), NULL);
781 }
782
783 /*
784 **
785 */
786 static gboolean ui_bud_manage_cleanup(struct ui_bud_manage_data *data, gint result)
787 {
788 gboolean doupdate = FALSE;
789
790 DB( g_print("(ui_bud_manage) cleanup\n") );
791
792
793 if(data->lastcatitem != NULL)
794 {
795 DB( g_print(" -> should do a get for last selected (%s)\n", data->lastcatitem->name) );
796 ui_bud_manage_getlast(data);
797 }
798
799
800 //do_application_specific_something ();
801 DB( g_print(" accept\n") );
802
803 GLOBALS->changes_count += data->change;
804
805 DB( g_print(" free tmp_list\n") );
806
807 return doupdate;
808 }
809
810
811 /*
812 **
813 */
814 static void ui_bud_manage_setup(struct ui_bud_manage_data *data)
815 {
816
817 DB( g_print("(ui_bud_manage) setup\n") );
818
819 data->tmp_list = NULL;
820 data->change = 0;
821 data->cat = NULL;
822 data->lastcatitem = NULL;
823
824 ui_cat_listview_populate(data->LV_cat);
825 gtk_tree_view_expand_all (GTK_TREE_VIEW(data->LV_cat));
826 }
827
828
829
830 // the window creation
831 GtkWidget *ui_bud_manage_dialog (void)
832 {
833 struct ui_bud_manage_data data;
834 GtkWidget *window, *content, *bbox, *mainbox, *treeview, *scrollwin, *vbox, *radio, *table, *label, *widget;
835 GtkWidget *spinner;
836 GtkWidget *alignment, *hpaned;
837 guint i, row;
838
839 memset(&data, 0, sizeof(struct ui_bud_manage_data));
840
841 window = gtk_dialog_new_with_buttons (_("Manage Budget"),
842 GTK_WINDOW(GLOBALS->mainwindow),
843 0,
844 GTK_STOCK_CLOSE,
845 GTK_RESPONSE_ACCEPT,
846 NULL);
847
848 data.window = window;
849
850 //homebank_window_set_icon_from_file(GTK_WINDOW (window), "budget.svg");
851 gtk_window_set_icon_name(GTK_WINDOW (window), HB_STOCK_BUDGET);
852
853 //store our window private data
854 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)&data);
855 DB( g_print("(ui_bud_manage) window=%p, inst_data=%p\n", window, &data) );
856
857
858 //window contents
859 content = gtk_dialog_get_content_area(GTK_DIALOG (window));
860 mainbox = gtk_hbox_new (FALSE, HB_BOX_SPACING);
861 gtk_box_pack_start (GTK_BOX (content), mainbox, TRUE, TRUE, 0);
862 gtk_container_set_border_width (GTK_CONTAINER(mainbox), HB_MAINBOX_SPACING);
863
864 hpaned = gtk_hpaned_new();
865 gtk_box_pack_start (GTK_BOX (mainbox), hpaned, TRUE, TRUE, 0);
866
867 /* left area */
868 vbox = gtk_vbox_new (FALSE, HB_BOX_SPACING);
869 //gtk_box_pack_start (GTK_BOX (mainbox), vbox, FALSE, FALSE, 0);
870 gtk_paned_pack1 (GTK_PANED(hpaned), vbox, FALSE, FALSE);
871
872 //listview
873 scrollwin = gtk_scrolled_window_new(NULL,NULL);
874 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN);
875 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
876 gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0);
877 treeview = (GtkWidget *)ui_bud_listview_new();
878 data.LV_cat = treeview;
879 gtk_widget_set_size_request(treeview, HB_MINWIDTH_LIST, -1);
880 gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
881
882 /* right area */
883 vbox = gtk_vbox_new (FALSE, HB_BOX_SPACING);
884 //gtk_box_pack_start (GTK_BOX (mainbox), vbox, TRUE, TRUE, 0);
885 gtk_paned_pack2 (GTK_PANED(hpaned), vbox, FALSE, FALSE);
886
887
888 table = gtk_table_new (12, 5, FALSE);
889 gtk_table_set_row_spacings (GTK_TABLE (table), HB_TABROW_SPACING);
890 gtk_table_set_col_spacings (GTK_TABLE (table), HB_TABCOL_SPACING);
891
892 // gtk_alignment_new(xalign, yalign, xscale, yscale)
893 alignment = gtk_alignment_new(0.5, 0.0, 1.0, 0.0);
894 gtk_container_add(GTK_CONTAINER(alignment), table);
895 gtk_container_add (GTK_CONTAINER (vbox), alignment);
896
897
898 //gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
899
900 row = 0;
901 label = make_label(_("Budget for each month"), 0.0, 0.5);
902 gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1);
903 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 5, row, row+1);
904
905 row++;
906 label = make_label("", 0.0, 0.5);
907 gtk_misc_set_padding (GTK_MISC (label), HB_BOX_SPACING, 0);
908 gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
909
910 radio = gtk_radio_button_new_with_label (NULL, _("is the same"));
911 data.CM_type[0] = radio;
912 gtk_table_attach_defaults (GTK_TABLE (table), radio, 1, 5, row, row+1);
913
914 row++;
915 //label = make_label(_("Each"), 1.0, 0.5);
916 //gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, row, row+1);
917 spinner = make_amount(label);
918 data.spinner[0] = spinner;
919 gtk_table_attach_defaults (GTK_TABLE (table), spinner, 2, 3, row, row+1);
920
921 widget = gtk_button_new_with_mnemonic (_("_Clear input"));
922 data.BT_clear = widget;
923 gtk_table_attach_defaults (GTK_TABLE (table), widget, 4, 5, row, row+1);
924
925
926 // propagate button
927 /*row++;
928 button = gtk_button_new_with_label(_("Propagate"));
929 gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, row, row+1);
930 */
931
932 row++;
933 radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON (radio), _("is different"));
934 data.CM_type[1] = radio;
935 gtk_table_attach_defaults (GTK_TABLE (table), radio, 1, 5, row, row+1);
936
937 for(i=0;i<12;i++)
938 {
939 gint col;
940
941 col = ((i<6) ? 1 : 3);
942 row = 4 + ((i<6) ? i : i-6);
943 //col = 0;
944 //row = 5 + i;
945
946 label = make_label(months[i], 0, 0.5);
947 gtk_table_attach_defaults (GTK_TABLE (table), label, col, col+1, row, row+1);
948
949 spinner = make_amount(label);
950 data.spinner[i+1] = spinner;
951 gtk_table_attach_defaults (GTK_TABLE (table), spinner, col+1, col+2, row, row+1);
952
953 DB( g_print("(ui_bud_manage) %s, col=%d, row=%d", months[i], col, row) );
954 }
955
956 row++;
957 label = make_label(_("Options"), 0.0, 0.5);
958 gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1);
959 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 5, row, row+1);
960
961 row++;
962 widget = gtk_check_button_new_with_mnemonic (_("_Force monitoring this category"));
963 data.CM_force = widget;
964 gtk_table_attach_defaults (GTK_TABLE (table), widget, 1, 5, row, row+1);
965
966
967 // button box
968 bbox = gtk_hbox_new (FALSE, HB_BOX_SPACING);
969 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
970 //gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
971 gtk_box_set_spacing (GTK_BOX (bbox), HB_BOX_SPACING);
972
973 data.BT_import = gtk_button_new_with_mnemonic(_("_Import"));
974 //data.BT_import = gtk_button_new_from_stock(GTK_STOCK_OPEN);
975 gtk_box_pack_start (GTK_BOX (bbox), data.BT_import, FALSE, FALSE, 0);
976
977 data.BT_export = gtk_button_new_with_mnemonic(_("E_xport"));
978 //data.BT_export = gtk_button_new_from_stock(GTK_STOCK_SAVE);
979 gtk_box_pack_start (GTK_BOX (bbox), data.BT_export, FALSE, FALSE, 0);
980
981
982 //connect all our signals
983 g_signal_connect (window, "destroy",
984 G_CALLBACK (gtk_widget_destroyed), &window);
985
986
987 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_cat)), "changed", G_CALLBACK (ui_bud_manage_selection), NULL);
988 //g_signal_connect (GTK_TREE_VIEW(data.LV_cat), "row-activated", G_CALLBACK (ui_bud_manage_onRowActivated), NULL);
989
990 data.handler_id[HID_CUSTOM] = g_signal_connect (data.CM_type[0], "toggled", G_CALLBACK (ui_bud_manage_toggle), NULL);
991
992
993 g_signal_connect (G_OBJECT (data.BT_clear), "clicked", G_CALLBACK (ui_bud_manage_clear), NULL);
994
995 g_signal_connect (G_OBJECT (data.BT_import), "clicked", G_CALLBACK (ui_bud_manage_load_csv), NULL);
996 g_signal_connect (G_OBJECT (data.BT_export), "clicked", G_CALLBACK (ui_bud_manage_save_csv), NULL);
997
998 //data.custom = FALSE;
999 //gtk_widget_set_sensitive(data.table, FALSE);
1000
1001 //setup, init and show window
1002 ui_bud_manage_setup(&data);
1003 ui_bud_manage_update(window, NULL);
1004
1005
1006
1007 gtk_widget_show_all (window);
1008
1009 //result
1010 gint result = gtk_dialog_run (GTK_DIALOG (window));
1011 switch (result)
1012 {
1013 case GTK_RESPONSE_ACCEPT:
1014 //do_application_specific_something ();
1015 break;
1016 default:
1017 //do_nothing_since_dialog_was_cancelled ();
1018 break;
1019 }
1020
1021 // cleanup and destroy
1022 ui_bud_manage_cleanup(&data, result);
1023 gtk_widget_destroy (window);
1024
1025 return NULL;
1026 }
1027
This page took 0.100599 seconds and 4 git commands to generate.