]> Dogcows Code - chaz/homebank/blob - src/dsp-account.c
import homebank-5.2.7
[chaz/homebank] / src / dsp-account.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 "dsp-account.h"
24 #include "dsp-mainwindow.h"
25
26 #include "list-operation.h"
27 #include "hub-account.h"
28
29 #include "ui-widgets.h"
30 #include "ui-filter.h"
31 #include "ui-transaction.h"
32 #include "ui-txn-multi.h"
33
34 /****************************************************************************/
35 /* Debug macros */
36 /****************************************************************************/
37 #define MYDEBUG 0
38
39 #if MYDEBUG
40 #define DB(x) (x);
41 #else
42 #define DB(x);
43 #endif
44
45 /* our global datas */
46 extern struct HomeBank *GLOBALS;
47 extern struct Preferences *PREFS;
48
49 //debug
50 #define UI 1
51
52
53 extern gchar *CYA_FLT_TYPE[];
54 extern gchar *CYA_FLT_STATUS[];
55
56
57 static void register_panel_collect_filtered_txn(GtkWidget *view, gboolean emptysearch);
58 static void register_panel_listview_populate(GtkWidget *view);
59 static void register_panel_action(GtkWidget *widget, gpointer user_data);
60 static void register_panel_update(GtkWidget *widget, gpointer user_data);
61
62 static void register_panel_export_csv(GtkWidget *widget, gpointer user_data);
63
64 static void register_panel_make_archive(GtkWidget *widget, gpointer user_data);
65
66 static void status_selected_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata);
67
68 static void register_panel_edit_multiple(GtkWidget *widget, Transaction *txn, gint column_id, gpointer user_data);
69
70 static void register_panel_selection(GtkTreeSelection *treeselection, gpointer user_data);
71 static void register_panel_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata);
72
73
74 /* account action functions -------------------- */
75
76 static void register_panel_action_editfilter(GtkAction *action, gpointer user_data)
77 {
78 struct register_panel_data *data = user_data;
79
80 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_FILTER));
81 }
82
83
84 static void register_panel_action_add(GtkAction *action, gpointer user_data)
85 {
86 struct register_panel_data *data = user_data;
87
88 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_ADD));
89 }
90
91 static void register_panel_action_inherit(GtkAction *action, gpointer user_data)
92 {
93 struct register_panel_data *data = user_data;
94
95 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_INHERIT));
96 }
97
98 static void register_panel_action_edit(GtkAction *action, gpointer user_data)
99 {
100 struct register_panel_data *data = user_data;
101
102 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_EDIT));
103 }
104
105 static void register_panel_action_multiedit(GtkAction *action, gpointer user_data)
106 {
107 struct register_panel_data *data = user_data;
108
109 register_panel_edit_multiple(data->window, NULL, 0, user_data);
110 }
111
112 static void register_panel_action_reconcile(GtkAction *action, gpointer user_data)
113 {
114 struct register_panel_data *data = user_data;
115
116 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_RECONCILE));
117 }
118
119 static void register_panel_action_clear(GtkAction *action, gpointer user_data)
120 {
121 struct register_panel_data *data = user_data;
122
123 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_CLEAR));
124 }
125
126 static void register_panel_action_none(GtkAction *action, gpointer user_data)
127 {
128 struct register_panel_data *data = user_data;
129
130 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_NONE));
131 }
132
133 static void register_panel_action_remove(GtkAction *action, gpointer user_data)
134 {
135 struct register_panel_data *data = user_data;
136
137 register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_DELETE));
138 }
139
140
141
142 static void register_panel_action_createtemplate(GtkAction *action, gpointer user_data)
143 {
144 struct register_panel_data *data = user_data;
145
146 register_panel_make_archive(data->window, NULL);
147 }
148
149
150
151 static void register_panel_action_exportcsv(GtkAction *action, gpointer user_data)
152 {
153 struct register_panel_data *data = user_data;
154
155 register_panel_export_csv(data->window, NULL);
156 }
157
158
159 /* = = = = = = = = future version = = = = = = = = */
160
161 static void register_panel_action_exportpdf(GtkAction *action, gpointer user_data)
162 {
163 struct register_panel_data *data = user_data;
164 gchar *name, *filepath;
165
166 if(data->showall == FALSE)
167 {
168 name = g_strdup_printf("%s.pdf", data->acc->name);
169 filepath = g_build_filename(PREFS->path_export, name, NULL);
170 g_free(name);
171
172 if( ui_dialog_export_pdf(GTK_WINDOW(data->window), &filepath) == GTK_RESPONSE_ACCEPT )
173 {
174 DB( g_printf(" filename is'%s'\n", filepath) );
175
176
177 hb_export_pdf_listview(GTK_TREE_VIEW(data->LV_ope), filepath, data->acc->name);
178 }
179
180 g_free(filepath);
181
182 }
183 }
184
185
186 static void register_panel_action_duplicate_mark(GtkAction *action, gpointer user_data)
187 {
188 struct register_panel_data *data = user_data;
189
190 DB( g_print("check duplicate\n\n") );
191
192 // open dialog to select date tolerance in days
193 // with info message
194 // with check/fix button and progress bar
195 // parse listview txn, clear/mark duplicate
196 // apply filter
197
198 if(data->showall == FALSE)
199 {
200 gint daygap;
201
202 daygap = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_txn_daygap));
203 data->similar = transaction_similar_mark (data->acc, daygap);
204 if( data->similar > 0 )
205 {
206 gchar *text = g_strdup_printf(_("There is %d group of similar transactions"), data->similar);
207 gtk_label_set_text(GTK_LABEL(data->LB_duplicate), text);
208 g_free(text);
209 }
210 else
211 gtk_label_set_text(GTK_LABEL(data->LB_duplicate), _("No similar transaction were found !"));
212
213 gtk_widget_show(data->IB_duplicate);
214 //#GTK+710888: hack waiting a fix
215 gtk_widget_queue_resize (data->IB_duplicate);
216
217 gtk_widget_queue_draw (data->LV_ope);
218 }
219
220
221 }
222
223
224 static void register_panel_action_duplicate_unmark(GtkAction *action, gpointer user_data)
225 {
226 struct register_panel_data *data = user_data;
227
228 DB( g_print("uncheck duplicate\n\n") );
229
230 if(data->showall == FALSE)
231 {
232 data->similar = 0;
233 gtk_widget_hide(data->IB_duplicate);
234 transaction_similar_unmark(data->acc);
235 gtk_widget_queue_draw (data->LV_ope);
236 }
237 }
238
239
240 static void register_panel_action_check_internal_xfer(GtkAction *action, gpointer user_data)
241 {
242 struct register_panel_data *data = user_data;
243 GtkTreeModel *model;
244 GtkTreeIter iter;
245 GList *badxferlist;
246 gboolean valid;
247 gint count;
248
249 DB( g_print("check intenal xfer\n\n") );
250
251 badxferlist = NULL;
252 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope));
253 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
254 while (valid)
255 {
256 Transaction *txn;
257
258 gtk_tree_model_get (model, &iter,
259 MODEL_TXN_POINTER, &txn,
260 -1);
261
262 if( txn->paymode == PAYMODE_INTXFER )
263 {
264 if( transaction_xfer_child_strong_get(txn) == NULL )
265 {
266 DB( g_print(" - invalid xfer: '%s'\n", txn->memo) );
267
268 //test unrecoverable (kxferacc = 0)
269 if( txn->kxferacc <= 0 )
270 {
271 DB( g_print(" - unrecoverable, revert to normal xfer\n") );
272 txn->flags |= OF_CHANGED;
273 txn->paymode = PAYMODE_XFER;
274 txn->kxfer = 0;
275 txn->kxferacc = 0;
276 }
277 else
278 {
279 badxferlist = g_list_append(badxferlist, txn);
280 }
281 }
282 }
283
284 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
285 }
286
287 count = g_list_length (badxferlist);
288 DB( g_print(" - found %d invalid int xfer\n", count) );
289
290 if(count <= 0)
291 {
292 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_INFO,
293 _("Check internal transfer result"),
294 _("No inconsistency found !")
295 );
296 }
297 else
298 {
299 gboolean do_fix;
300
301 do_fix = ui_dialog_msg_question(
302 GTK_WINDOW(data->window),
303 _("Check internal transfer result"),
304 _("Inconsistency were found: %d\n"
305 "do you want to review and fix ?"),
306 count
307 );
308
309 if(do_fix == GTK_RESPONSE_YES)
310 {
311 GList *tmplist = g_list_first(badxferlist);
312
313 while (tmplist != NULL)
314 {
315 Transaction *stxn = tmplist->data;
316
317 //future (open dialog to select date tolerance in days)
318 transaction_xfer_search_or_add_child(GTK_WINDOW(data->window), stxn, 0);
319
320 tmplist = g_list_next(tmplist);
321 }
322 }
323 }
324
325 g_list_free (badxferlist);
326
327 }
328
329
330 static void register_panel_action_exportqif(GtkAction *action, gpointer user_data)
331 {
332 struct register_panel_data *data = user_data;
333 gchar *filename;
334
335 // noaction if show all account
336 if(data->showall)
337 return;
338
339 DB( g_print("(qif) test qif export\n\n") );
340
341 if( ui_file_chooser_qif(GTK_WINDOW(data->window), &filename) == TRUE )
342 {
343 hb_export_qif_account_single(filename, data->acc);
344 g_free( filename );
345 }
346 }
347
348
349 static void register_panel_action_converttoeuro(GtkAction *action, gpointer user_data)
350 {
351 struct register_panel_data *data = user_data;
352 gchar *msg;
353 gint result;
354
355 // noaction if show all account
356 if(data->showall)
357 return;
358
359 DB( g_print("action convert to euro\n") );
360
361 msg = g_strdup_printf(_("Every transaction amount will be divided by %.6f."), PREFS->euro_value);
362
363 result = ui_dialog_msg_confirm_alert(
364 GTK_WINDOW(data->window),
365 _("Are you sure you want to convert this account\nto Euro as Major currency?"),
366 msg,
367 _("_Convert")
368 );
369
370 g_free(msg);
371
372 if(result == GTK_RESPONSE_OK)
373 {
374 account_convert_euro(data->acc);
375 register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_BALANCE));
376 }
377 }
378
379
380 static void register_panel_action_assign(GtkAction *action, gpointer user_data)
381 {
382 struct register_panel_data *data = user_data;
383 gint count;
384 gboolean usermode = TRUE;
385
386 // noaction if show all account
387 if(data->showall)
388 return;
389
390 DB( g_print("action assign\n") );
391
392 count = transaction_auto_assign(g_queue_peek_head_link(data->acc->txn_queue), data->acc->key);
393 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_ope));
394 GLOBALS->changes_count += count;
395
396 //inform the user
397 if(usermode == TRUE)
398 {
399 gchar *txt;
400
401 if(count == 0)
402 txt = _("No transaction changed");
403 else
404 txt = _("transaction changed: %d");
405
406 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_INFO,
407 _("Automatic assignment result"),
408 txt,
409 count);
410 }
411
412 //refresh main
413 if( count > 0 )
414 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
415
416 }
417
418
419 static void register_panel_action_close(GtkAction *action, gpointer user_data)
420 {
421 struct register_panel_data *data = user_data;
422
423 DB( g_print("action close\n") );
424
425 DB( g_print("window %p\n", data->window) );
426
427 gtk_widget_destroy (GTK_WIDGET (data->window));
428
429 //g_signal_emit_by_name(data->window, "delete-event", NULL, &result);
430
431 }
432
433
434 /* these 5 functions are independant from account window */
435
436 /* account functions -------------------- */
437
438 static void register_panel_export_csv(GtkWidget *widget, gpointer user_data)
439 {
440 struct register_panel_data *data;
441 gchar *filename = NULL;
442 GString *node;
443 GIOChannel *io;
444
445 DB( g_print("\n[account] export csv\n") );
446
447 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
448
449 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, NULL) == TRUE )
450 {
451 DB( g_print(" + filename is %s\n", filename) );
452 io = g_io_channel_new_file(filename, "w", NULL);
453 if(io != NULL)
454 {
455 node = list_txn_to_string(GTK_TREE_VIEW(data->LV_ope), FALSE);
456 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
457 g_io_channel_unref (io);
458 g_string_free(node, TRUE);
459 }
460 g_free( filename );
461 }
462 }
463
464
465 static void register_panel_edit_multiple(GtkWidget *widget, Transaction *txn, gint column_id, gpointer user_data)
466 {
467 struct register_panel_data *data;
468 GtkWidget *dialog;
469
470 DB( g_print("\n[account] edit multiple\n") );
471
472 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
473
474 DB( g_print(" - txn:%p, column: %d\n", txn, column_id) );
475
476 dialog = ui_multipleedit_dialog_new(GTK_WINDOW(data->window), GTK_TREE_VIEW(data->LV_ope));
477
478 if(txn != NULL && column_id != 0)
479 {
480 ui_multipleedit_dialog_prefill(dialog, txn, column_id);
481 }
482
483 //wait for the user
484 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
485
486 if( result == GTK_RESPONSE_ACCEPT )
487 {
488 gboolean do_sort;
489 gint changes;
490
491 //#1792808: sort if date changed
492 changes = ui_multipleedit_dialog_apply (dialog, &do_sort);
493 data->do_sort = do_sort;
494 if( changes > 0 )
495 {
496 //#1782749 update account status
497 if( data->acc != NULL )
498 data->acc->flags |= AF_CHANGED;
499
500 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
501 }
502 }
503
504 gtk_widget_destroy (dialog);
505
506 register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_BALANCE));
507 }
508
509
510 /*
511 ** make an archive with the active transaction
512 */
513 static void register_panel_make_archive(GtkWidget *widget, gpointer user_data)
514 {
515 struct register_panel_data *data;
516 GtkTreeModel *model;
517 GList *selection, *list;
518 gint result, count;
519
520 DB( g_print("\n[account] make archive\n") );
521
522 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
523
524
525 count = gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)));
526
527 if( count > 0 )
528 {
529
530 result = ui_dialog_msg_confirm_alert(
531 GTK_WINDOW(data->window),
532 NULL,
533 _("Do you want to create a template with\neach of the selected transaction ?"),
534 _("_Create")
535 );
536
537 /*
538 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
539 _("%d archives will be created"),
540 GLOBALS->changes_count
541 );
542 */
543
544 if(result == GTK_RESPONSE_OK)
545 {
546 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope));
547 selection = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)), &model);
548
549 list = g_list_first(selection);
550 while(list != NULL)
551 {
552 Archive *item;
553 Transaction *ope;
554 GtkTreeIter iter;
555
556 gtk_tree_model_get_iter(model, &iter, list->data);
557 gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &ope, -1);
558
559 DB( g_print(" create archive %s %.2f\n", ope->memo, ope->amount) );
560
561 item = da_archive_malloc();
562
563 da_archive_init_from_transaction(item, ope);
564
565 //GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item);
566 da_archive_append_new(item);
567 GLOBALS->changes_count++;
568
569 list = g_list_next(list);
570 }
571
572 g_list_foreach(selection, (GFunc)gtk_tree_path_free, NULL);
573 g_list_free(selection);
574 }
575 }
576 }
577
578
579 static void register_panel_cb_bar_duplicate_response(GtkWidget *info_bar, gint response_id, gpointer user_data)
580 {
581 struct register_panel_data *data;
582
583 DB( g_print("\n[account] bar_duplicate_response\n") );
584
585 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(info_bar, GTK_TYPE_WINDOW)), "inst_data");
586
587 switch( response_id )
588 {
589 case HB_RESPONSE_REFRESH:
590 register_panel_action_duplicate_mark(NULL, data);
591 break;
592 case GTK_RESPONSE_CLOSE:
593 register_panel_action_duplicate_unmark(NULL, data);
594 gtk_widget_hide (GTK_WIDGET (info_bar));
595 break;
596 }
597 }
598
599
600 static void register_panel_cb_filter_daterange(GtkWidget *widget, gpointer user_data)
601 {
602 struct register_panel_data *data;
603 gboolean future;
604 gint range;
605
606 DB( g_print("\n[account] filter_daterange\n") );
607
608 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
609
610 range = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_range));
611 future = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_future));
612
613 data->filter->nbdaysfuture = 0;
614
615 if(range != FLT_RANGE_OTHER)
616 {
617 filter_preset_daterange_set(data->filter, range, (data->showall == FALSE) ? data->acc->key : 0);
618 // add eventual x days into future display
619 if( future && (PREFS->date_future_nbdays > 0) )
620 filter_preset_daterange_add_futuregap(data->filter, PREFS->date_future_nbdays);
621
622 register_panel_collect_filtered_txn(data->LV_ope, FALSE);
623 register_panel_listview_populate(data->LV_ope);
624 }
625 else
626 {
627 if(ui_flt_manage_dialog_new(GTK_WINDOW(data->window), data->filter, data->showall, TRUE) != GTK_RESPONSE_REJECT)
628 {
629 register_panel_collect_filtered_txn(data->LV_ope, FALSE);
630 register_panel_listview_populate(data->LV_ope);
631 register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_SENSITIVE+UF_BALANCE));
632 }
633 }
634 }
635
636
637 static void register_panel_cb_filter_type(GtkWidget *widget, gpointer user_data)
638 {
639 struct register_panel_data *data;
640 gint type;
641
642 DB( g_print("\n[account] filter_type\n") );
643 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
644
645 type = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_type));
646
647 filter_preset_type_set(data->filter, type);
648
649 register_panel_collect_filtered_txn(data->LV_ope, FALSE);
650 register_panel_listview_populate(data->LV_ope);
651 }
652
653
654 static void register_panel_cb_filter_status(GtkWidget *widget, gpointer user_data)
655 {
656 struct register_panel_data *data;
657 gint status;
658
659 DB( g_print("\n[account] filter_status\n") );
660 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
661
662 status = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_status));
663
664 filter_preset_status_set(data->filter, status);
665
666 register_panel_collect_filtered_txn(data->LV_ope, FALSE);
667 register_panel_listview_populate(data->LV_ope);
668 }
669
670
671 static void register_panel_cb_filter_reset(GtkWidget *widget, gpointer user_data)
672 {
673 struct register_panel_data *data;
674
675 DB( g_print("\n[account] filter_reset\n") );
676 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
677
678 filter_reset(data->filter);
679
680 filter_preset_daterange_set (data->filter, PREFS->date_range_txn, (data->showall == FALSE) ? data->acc->key : 0);
681
682 if(PREFS->hidereconciled)
683 filter_preset_status_set (data->filter, FLT_STATUS_UNRECONCILED);
684
685 // add eventual x days into future display
686 if( PREFS->date_future_nbdays > 0 )
687 filter_preset_daterange_add_futuregap(data->filter, PREFS->date_future_nbdays);
688
689 register_panel_collect_filtered_txn(data->LV_ope, TRUE);
690 register_panel_listview_populate(data->LV_ope);
691
692 g_signal_handler_block(data->CY_range, data->handler_id[HID_RANGE]);
693 g_signal_handler_block(data->CY_type, data->handler_id[HID_TYPE]);
694 g_signal_handler_block(data->CY_status, data->handler_id[HID_STATUS]);
695
696 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), data->filter->range);
697 gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_type), data->filter->type);
698 gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_status), data->filter->status);
699
700 g_signal_handler_unblock(data->CY_status, data->handler_id[HID_STATUS]);
701 g_signal_handler_unblock(data->CY_type, data->handler_id[HID_TYPE]);
702 g_signal_handler_unblock(data->CY_range, data->handler_id[HID_RANGE]);
703
704 }
705
706
707 static void register_panel_balance_refresh(GtkWidget *view)
708 {
709 struct register_panel_data *data;
710 GList *list;
711 gdouble balance;
712 GtkTreeModel *model;
713 guint32 ldate = 0;
714 gushort lpos = 1;
715
716 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(view, GTK_TYPE_WINDOW)), "inst_data");
717
718 // noaction if show all account
719 if(data->showall)
720 return;
721
722 DB( g_print("\n[account %d] balance refresh\n", data->acc != NULL ? (gint)data->acc->key : -1) );
723
724 balance = data->acc->initial;
725
726 //#1270687: sort if date changed
727 if(data->do_sort)
728 {
729 DB( g_print(" - complete txn sort\n") );
730
731 da_transaction_queue_sort(data->acc->txn_queue);
732 data->do_sort = FALSE;
733 }
734
735 list = g_queue_peek_head_link(data->acc->txn_queue);
736 while (list != NULL)
737 {
738 Transaction *ope = list->data;
739 gdouble value;
740
741 //#1267344
742 if(!(ope->status == TXN_STATUS_REMIND))
743 balance += ope->amount;
744
745 ope->balance = balance;
746
747 //#1661806 add show overdraft
748 //#1672209 added round like for #400483
749 ope->overdraft = FALSE;
750 value = hb_amount_round(balance, 2);
751 if( value != 0.0 && value < data->acc->minimum )
752 ope->overdraft = TRUE;
753
754 if(ope->date == ldate)
755 {
756 ope->pos = ++lpos;
757 }
758 else
759 {
760 ope->pos = lpos = 1;
761 }
762 ldate = ope->date;
763
764 list = g_list_next(list);
765 }
766
767 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope));
768 list_txn_sort_force(GTK_TREE_SORTABLE(model), NULL);
769
770 }
771
772
773 static void register_panel_collect_filtered_txn(GtkWidget *view, gboolean emptysearch)
774 {
775 struct register_panel_data *data;
776 GList *lst_acc, *lnk_acc;
777 GList *lnk_txn;
778
779 DB( g_print("\n[register_panel] collect_filtered_txn\n") );
780
781 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(view, GTK_TYPE_WINDOW)), "inst_data");
782
783 if(data->gpatxn != NULL)
784 g_ptr_array_free (data->gpatxn, TRUE);
785
786 //todo: why this ?
787 data->gpatxn = g_ptr_array_sized_new(64);
788
789 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
790 lnk_acc = g_list_first(lst_acc);
791 while (lnk_acc != NULL)
792 {
793 Account *acc = lnk_acc->data;
794
795 // skip closed in showall mode
796 if( data->showall == TRUE && (acc->flags & AF_CLOSED) )
797 goto next_acc;
798
799 // skip other than current in normal mode
800 if( (data->showall == FALSE) && (data->acc != NULL) && (acc->key != data->acc->key) )
801 goto next_acc;
802
803 lnk_txn = g_queue_peek_head_link(acc->txn_queue);
804 while (lnk_txn != NULL)
805 {
806 Transaction *ope = lnk_txn->data;
807
808 if(filter_txn_match(data->filter, ope) == 1)
809 {
810 //add to the list
811 g_ptr_array_add(data->gpatxn, (gpointer)ope);
812 }
813 lnk_txn = g_list_next(lnk_txn);
814 }
815
816 next_acc:
817 lnk_acc = g_list_next(lnk_acc);
818 }
819 g_list_free(lst_acc);
820
821 //#1789698 not always empty
822 if( emptysearch == TRUE )
823 {
824 g_signal_handler_block(data->ST_search, data->handler_id[HID_SEARCH]);
825 gtk_entry_set_text (GTK_ENTRY(data->ST_search), "");
826 g_signal_handler_unblock(data->ST_search, data->handler_id[HID_SEARCH]);
827 }
828 }
829
830
831 static void register_panel_listview_populate(GtkWidget *widget)
832 {
833 struct register_panel_data *data;
834 GtkTreeModel *model;
835 GtkTreeIter iter;
836 gboolean hastext;
837 gchar *needle;
838 gint sort_column_id;
839 GtkSortType order;
840 guint i, qs_flag;
841
842 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
843
844 DB( g_print("\n[register_panel] listview_populate\n") );
845
846 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope));
847
848 // ref model to keep it
849 //g_object_ref(model);
850 //gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_ope), NULL);
851 gtk_list_store_clear (GTK_LIST_STORE(model));
852
853
854 // perf: if you leave the sort, insert is damned slow
855 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), &sort_column_id, &order);
856
857 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, PREFS->lst_ope_sort_order);
858
859 hastext = gtk_entry_get_text_length (GTK_ENTRY(data->ST_search)) >= 2;
860 needle = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_search));
861
862 //build the mask flag for quick search
863 qs_flag = 0;
864 if(hastext)
865 {
866 qs_flag = list_txn_get_quicksearch_column_mask(GTK_TREE_VIEW(data->LV_ope));
867 }
868
869 data->total = 0;
870 data->totalsum = 0.0;
871
872 for(i=0;i<data->gpatxn->len;i++)
873 {
874 Transaction *txn = g_ptr_array_index(data->gpatxn, i);
875 gboolean insert = TRUE;
876
877 if(hastext)
878 {
879 insert = filter_txn_search_match(needle, txn, qs_flag);
880 }
881
882 if(insert)
883 {
884 //gtk_list_store_append (GTK_LIST_STORE(model), &iter);
885 //gtk_list_store_set (GTK_LIST_STORE(model), &iter,
886 gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter, -1,
887 MODEL_TXN_POINTER, txn,
888 -1);
889
890 if( data->showall == FALSE )
891 data->totalsum += txn->amount;
892 else
893 data->totalsum += hb_amount_base (txn->amount, txn->kcur);
894
895 data->total++;
896 }
897 }
898
899 //gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_ope), model); /* Re-attach model to view */
900 //g_object_unref(model);
901
902 // push back the sort id
903 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), sort_column_id, order);
904
905 /* update info range text */
906 {
907 gchar *daterange;
908
909 daterange = filter_daterange_text_get(data->filter);
910 gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange);
911
912 g_free(daterange);
913 }
914
915 register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_SENSITIVE+UF_BALANCE));
916
917 }
918
919 static gint txn_list_get_count_reconciled(GtkTreeView *treeview)
920 {
921 GtkTreeModel *model;
922 GList *lselection, *list;
923 gint count = 0;
924
925 model = gtk_tree_view_get_model(treeview);
926 lselection = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(treeview), &model);
927
928 list = g_list_last(lselection);
929 while(list != NULL)
930 {
931 GtkTreeIter iter;
932 Transaction *txn;
933
934
935 gtk_tree_model_get_iter(model, &iter, list->data);
936 gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &txn, -1);
937 if(txn->status == TXN_STATUS_RECONCILED)
938 count++;
939
940 list = g_list_previous(list);
941 }
942
943 g_list_foreach(lselection, (GFunc)gtk_tree_path_free, NULL);
944 g_list_free(lselection);
945
946 return count;
947 }
948
949
950 static void txn_list_add_by_value(GtkTreeView *treeview, Transaction *ope)
951 {
952 GtkTreeModel *model;
953 GtkTreeIter iter;
954 //GtkTreePath *path;
955 //GtkTreeSelection *sel;
956
957 DB( g_print("\n[transaction] add_treeview\n") );
958
959 model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
960 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
961 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
962 MODEL_TXN_POINTER, ope,
963 -1);
964
965 //activate that new line
966 //path = gtk_tree_model_get_path(model, &iter);
967 //gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path);
968
969 //sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
970 //gtk_tree_selection_select_iter(sel, &iter);
971
972 //gtk_tree_path_free(path);
973
974 }
975
976
977
978
979 /* used to remove a intxfer child from a treeview */
980 static void txn_list_remove_by_value(GtkTreeModel *model, Transaction *txn)
981 {
982 GtkTreeIter iter;
983 gboolean valid;
984
985 if( txn == NULL )
986 return;
987
988 DB( g_print("remove by value %p\n\n", txn) );
989
990 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
991 while (valid)
992 {
993 Transaction *tmp;
994
995 gtk_tree_model_get (model, &iter,
996 MODEL_TXN_POINTER, &tmp,
997 -1);
998
999 if( txn == tmp )
1000 {
1001 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1002 break;
1003 }
1004 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
1005 }
1006 }
1007
1008
1009 static void status_selected_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata)
1010 {
1011 gint targetstatus = GPOINTER_TO_INT(userdata);
1012 Transaction *txn;
1013
1014 gtk_tree_model_get(model, iter, MODEL_TXN_POINTER, &txn, -1);
1015
1016 account_balances_sub(txn);
1017
1018 switch(targetstatus)
1019 {
1020 case TXN_STATUS_NONE:
1021 switch(txn->status)
1022 {
1023 case TXN_STATUS_CLEARED:
1024 case TXN_STATUS_RECONCILED:
1025 txn->status = TXN_STATUS_NONE;
1026 txn->flags |= OF_CHANGED;
1027 break;
1028 }
1029 break;
1030
1031 case TXN_STATUS_CLEARED:
1032 switch(txn->status)
1033 {
1034 case TXN_STATUS_NONE:
1035 txn->status = TXN_STATUS_CLEARED;
1036 txn->flags |= OF_CHANGED;
1037 break;
1038 case TXN_STATUS_CLEARED:
1039 txn->status = TXN_STATUS_NONE;
1040 txn->flags |= OF_CHANGED;
1041 break;
1042 }
1043 break;
1044
1045 case TXN_STATUS_RECONCILED:
1046 switch(txn->status)
1047 {
1048 case TXN_STATUS_NONE:
1049 case TXN_STATUS_CLEARED:
1050 txn->status = TXN_STATUS_RECONCILED;
1051 txn->flags |= OF_CHANGED;
1052 break;
1053 case TXN_STATUS_RECONCILED:
1054 txn->status = TXN_STATUS_CLEARED;
1055 txn->flags |= OF_CHANGED;
1056 break;
1057 }
1058 break;
1059
1060 }
1061
1062 transaction_changed(txn);
1063
1064 account_balances_add(txn);
1065
1066 /* #492755 let the child transfer unchanged */
1067
1068 }
1069
1070
1071 static void delete_active_transaction(GtkTreeView *treeview)
1072 {
1073 GtkTreeModel *model;
1074 GList *list;
1075
1076 model = gtk_tree_view_get_model(treeview);
1077 list = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(treeview), &model);
1078
1079 if(list != NULL)
1080 {
1081 GtkTreeIter iter;
1082
1083 gtk_tree_model_get_iter(model, &iter, list->data);
1084 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1085 }
1086
1087 g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
1088 g_list_free(list);
1089
1090
1091 }
1092
1093
1094 static void register_panel_add_single_transaction(GtkWindow *window, Transaction *txn)
1095 {
1096 struct register_panel_data *data;
1097
1098 DB( g_print("\n[account] add single txn\n") );
1099
1100 data = g_object_get_data(G_OBJECT(window), "inst_data");
1101
1102 txn_list_add_by_value(GTK_TREE_VIEW(data->LV_ope), txn);
1103 }
1104
1105
1106 static void register_panel_action(GtkWidget *widget, gpointer user_data)
1107 {
1108 struct register_panel_data *data;
1109 gint action = GPOINTER_TO_INT(user_data);
1110 guint changes = GLOBALS->changes_count;
1111 gboolean result;
1112
1113 DB( g_print("\n[account] action\n") );
1114
1115 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1116 //data = INST_DATA(widget);
1117
1118 DB( g_print(" - action=%d\n", action) );
1119
1120 switch(action)
1121 {
1122 //add
1123 case ACTION_ACCOUNT_ADD:
1124 //inherit
1125 case ACTION_ACCOUNT_INHERIT:
1126 {
1127 GtkWidget *dialog;
1128 Transaction *src_txn;
1129 gint type = 0;
1130
1131 homebank_app_date_get_julian();
1132
1133 if(action == ACTION_ACCOUNT_ADD)
1134 {
1135 DB( g_print("(transaction) add multiple\n") );
1136 src_txn = da_transaction_malloc();
1137 src_txn->date = GLOBALS->today;
1138 if( data->acc != NULL )
1139 src_txn->kacc = data->acc->key;
1140 da_transaction_set_default_template(src_txn);
1141 type = TRANSACTION_EDIT_ADD;
1142 }
1143 else
1144 {
1145 DB( g_print("(transaction) inherit multiple\n") );
1146 src_txn = da_transaction_clone(list_txn_get_active_transaction(GTK_TREE_VIEW(data->LV_ope)));
1147 //#1432204
1148 src_txn->status = TXN_STATUS_NONE;
1149 type = TRANSACTION_EDIT_INHERIT;
1150 }
1151
1152 dialog = create_deftransaction_window(GTK_WINDOW(data->window), type, FALSE, (data->acc != NULL) ? data->acc->key : 0 );
1153 result = HB_RESPONSE_ADD;
1154 while(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP)
1155 {
1156 /* clone source transaction */
1157 if( result == HB_RESPONSE_ADD )
1158 {
1159 data->cur_ope = da_transaction_clone (src_txn);
1160
1161 if( PREFS->heritdate == FALSE ) //fix: 318733 / 1335285
1162 data->cur_ope->date = GLOBALS->today;
1163 }
1164
1165 deftransaction_set_transaction(dialog, data->cur_ope);
1166
1167 result = gtk_dialog_run (GTK_DIALOG (dialog));
1168 if(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT)
1169 {
1170 Transaction *add_txn;
1171
1172 deftransaction_get(dialog, NULL);
1173 add_txn = transaction_add(GTK_WINDOW(data->window), data->cur_ope);
1174 if((data->showall == TRUE) || ( (data->acc != NULL) && (data->cur_ope->kacc == data->acc->key) ) )
1175 {
1176 txn_list_add_by_value(GTK_TREE_VIEW(data->LV_ope), add_txn);
1177 //#1716181 also add to the ptr_array (quickfilter)
1178 g_ptr_array_add(data->gpatxn, (gpointer)add_txn);
1179 }
1180 register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE));
1181 //#1667201 already done into transaction_add
1182 //data->acc->flags |= AF_ADDED;
1183 GLOBALS->changes_count++;
1184 //store last date
1185 src_txn->date = data->cur_ope->date;
1186 }
1187
1188 if( result == HB_RESPONSE_ADD )
1189 {
1190 da_transaction_free (data->cur_ope);
1191 }
1192
1193 }
1194
1195 deftransaction_dispose(dialog, NULL);
1196 da_transaction_free (src_txn);
1197
1198 gtk_widget_destroy (dialog);
1199 }
1200 break;
1201
1202 case ACTION_ACCOUNT_EDIT:
1203 {
1204 Transaction *active_txn;
1205
1206 DB( g_print(" - edit\n") );
1207
1208 active_txn = list_txn_get_active_transaction(GTK_TREE_VIEW(data->LV_ope));
1209
1210 if(active_txn)
1211 {
1212 Transaction *old_txn, *new_txn;
1213
1214 old_txn = da_transaction_clone (active_txn);
1215 new_txn = active_txn;
1216
1217 result = deftransaction_external_edit(GTK_WINDOW(data->window), old_txn, new_txn);
1218
1219 if(result == GTK_RESPONSE_ACCEPT)
1220 {
1221 //manage current window display stuff
1222
1223 //#1270687: sort if date changed
1224 if(old_txn->date != new_txn->date)
1225 data->do_sort = TRUE;
1226
1227 // txn changed of account
1228 //TODO: maybe this should move to deftransaction_external_edit
1229 if( data->acc != NULL && (new_txn->kacc != data->acc->key) )
1230 {
1231 Account *nacc;
1232
1233 delete_active_transaction(GTK_TREE_VIEW(data->LV_ope));
1234 //#1667501 update target account window is open
1235 nacc = da_acc_get(new_txn->kacc);
1236 if( nacc != NULL && nacc->window != NULL )
1237 {
1238 DB( g_print("- account %d changed and window is open\n", nacc->key) );
1239 if( GTK_IS_WINDOW(nacc->window) )
1240 {
1241 register_panel_add_single_transaction(nacc->window, new_txn);
1242 register_panel_update(GTK_WIDGET(nacc->window), GINT_TO_POINTER(UF_BALANCE));
1243 }
1244 }
1245 }
1246
1247 //#1812470 txn is xfer update target account window is open
1248 if( (old_txn->paymode == PAYMODE_INTXFER) && (old_txn->amount != new_txn->amount) )
1249 {
1250 Account *nacc = da_acc_get(new_txn->kxferacc);
1251
1252 if( nacc != NULL && nacc->window != NULL )
1253 {
1254 if( GTK_IS_WINDOW(nacc->window) )
1255 {
1256 register_panel_update(GTK_WIDGET(nacc->window), GINT_TO_POINTER(UF_BALANCE));
1257 }
1258 }
1259 }
1260
1261 //da_transaction_copy(new_txn, old_txn);
1262
1263 register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE));
1264
1265 transaction_changed(new_txn);
1266
1267 GLOBALS->changes_count++;
1268 }
1269
1270 da_transaction_free (old_txn);
1271 }
1272 }
1273 break;
1274
1275 case ACTION_ACCOUNT_DELETE:
1276 {
1277 GtkTreeModel *model;
1278 GList *selection, *list;
1279 gint result;
1280
1281 DB( g_print(" - delete\n") );
1282
1283 result = ui_dialog_msg_confirm_alert(
1284 GTK_WINDOW(data->window),
1285 NULL,
1286 _("Do you want to delete\neach of the selected transaction ?"),
1287 _("_Delete")
1288 );
1289
1290 if(result == GTK_RESPONSE_OK)
1291 {
1292 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope));
1293 selection = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)), &model);
1294
1295 list = g_list_last(selection);
1296 while(list != NULL)
1297 {
1298 Transaction *entry;
1299 GtkTreeIter iter;
1300
1301 gtk_tree_model_get_iter(model, &iter, list->data);
1302 gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &entry, -1);
1303
1304 DB( g_print(" delete %s %.2f\n", entry->memo, entry->amount) );
1305
1306 //#1716181 also remove from the ptr_array (quickfilter)
1307 g_ptr_array_remove(data->gpatxn, (gpointer)entry);
1308
1309 // 1) remove visible current and potential xfer
1310 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1311 if(data->showall && entry->paymode == PAYMODE_INTXFER)
1312 {
1313 Transaction *child = transaction_xfer_child_strong_get(entry);
1314 if( child )
1315 {
1316 txn_list_remove_by_value(model, child);
1317 //#1716181 also remove from the ptr_array (quickfilter)
1318 g_ptr_array_remove(data->gpatxn, (gpointer)child);
1319 }
1320 }
1321
1322 // 2) remove datamodel
1323 transaction_remove(entry);
1324 GLOBALS->changes_count++;
1325
1326 list = g_list_previous(list);
1327 }
1328
1329 g_list_foreach(selection, (GFunc)gtk_tree_path_free, NULL);
1330 g_list_free(selection);
1331
1332 register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE));
1333 }
1334 }
1335 break;
1336
1337 //none
1338 case ACTION_ACCOUNT_NONE:
1339 {
1340 GtkTreeSelection *selection;
1341 gint count, result;
1342
1343 count = txn_list_get_count_reconciled(GTK_TREE_VIEW(data->LV_ope));
1344
1345 if(count > 0 )
1346 {
1347
1348 result = ui_dialog_msg_confirm_alert(
1349 GTK_WINDOW(data->window),
1350 _("Are you sure you want to change the status to None?"),
1351 _("Some transaction in your selection are already Reconciled."),
1352 _("_Change")
1353 );
1354 }
1355 else
1356 result = GTK_RESPONSE_OK;
1357
1358 if( result == GTK_RESPONSE_OK )
1359 {
1360 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope));
1361 gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)status_selected_foreach_func,
1362 GINT_TO_POINTER(TXN_STATUS_NONE));
1363
1364 DB( g_print(" - none\n") );
1365
1366 gtk_widget_queue_draw (data->LV_ope);
1367 //gtk_widget_queue_resize (data->LV_acc);
1368
1369 register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE));
1370
1371 GLOBALS->changes_count++;
1372 }
1373
1374 }
1375 break;
1376 //clear
1377 case ACTION_ACCOUNT_CLEAR:
1378 {
1379 GtkTreeSelection *selection;
1380
1381 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope));
1382 gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)status_selected_foreach_func,
1383 GINT_TO_POINTER(TXN_STATUS_CLEARED));
1384
1385 DB( g_print(" - clear\n") );
1386
1387 gtk_widget_queue_draw (data->LV_ope);
1388 //gtk_widget_queue_resize (data->LV_acc);
1389
1390 register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE));
1391
1392 GLOBALS->changes_count++;
1393 }
1394 break;
1395
1396
1397 //reconcile
1398 case ACTION_ACCOUNT_RECONCILE:
1399 {
1400 GtkTreeSelection *selection;
1401 gint count, result;
1402
1403 count = txn_list_get_count_reconciled(GTK_TREE_VIEW(data->LV_ope));
1404
1405 if(count > 0 )
1406 {
1407
1408 result = ui_dialog_msg_confirm_alert(
1409 GTK_WINDOW(data->window),
1410 _("Are you sure you want to toggle the status Reconciled?"),
1411 _("Some transaction in your selection are already Reconciled."),
1412 _("_Toggle")
1413 );
1414 }
1415 else
1416 result = GTK_RESPONSE_OK;
1417
1418 if( result == GTK_RESPONSE_OK )
1419 {
1420 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope));
1421 gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)status_selected_foreach_func,
1422 GINT_TO_POINTER(TXN_STATUS_RECONCILED));
1423
1424 DB( g_print(" - reconcile\n") );
1425
1426 gtk_widget_queue_draw (data->LV_ope);
1427 //gtk_widget_queue_resize (data->LV_acc);
1428
1429 register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE));
1430
1431 GLOBALS->changes_count++;
1432 }
1433
1434 }
1435 break;
1436
1437
1438 case ACTION_ACCOUNT_FILTER:
1439 {
1440
1441 if(ui_flt_manage_dialog_new(GTK_WINDOW(data->window), data->filter, data->showall, TRUE) != GTK_RESPONSE_REJECT)
1442 {
1443 register_panel_collect_filtered_txn(data->LV_ope, TRUE);
1444 register_panel_listview_populate(data->LV_ope);
1445 register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_SENSITIVE+UF_BALANCE));
1446
1447 g_signal_handler_block(data->CY_range, data->handler_id[HID_RANGE]);
1448 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), FLT_RANGE_OTHER);
1449 g_signal_handler_unblock(data->CY_range, data->handler_id[HID_RANGE]);
1450 }
1451
1452 }
1453 break;
1454
1455 }
1456
1457 //refresh main
1458 if( GLOBALS->changes_count > changes )
1459 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
1460
1461 }
1462
1463
1464
1465 static void register_panel_toggle_minor(GtkWidget *widget, gpointer user_data)
1466 {
1467 struct register_panel_data *data;
1468
1469 DB( g_print("\n[account] toggle\n") );
1470
1471 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1472
1473 register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_BALANCE));
1474 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_ope));
1475 }
1476
1477
1478 static void register_panel_selection(GtkTreeSelection *treeselection, gpointer user_data)
1479 {
1480
1481 DB( g_print("\n[account] selection changed cb\n") );
1482
1483
1484 register_panel_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE));
1485
1486 }
1487
1488
1489 static void register_panel_update(GtkWidget *widget, gpointer user_data)
1490 {
1491 struct register_panel_data *data;
1492 GtkTreeSelection *selection;
1493 gint flags = GPOINTER_TO_INT(user_data);
1494 gint count = 0;
1495
1496 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1497 //data = INST_DATA(widget);
1498
1499 DB( g_print("\n[account %d] update\n", data->acc != NULL ? (gint)data->acc->key : -1) );
1500
1501
1502 GLOBALS->minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
1503
1504 /* set window title */
1505 if(flags & UF_TITLE)
1506 {
1507 DB( g_print(" - UF_TITLE\n") );
1508
1509 }
1510
1511 /* update disabled things */
1512 if(flags & UF_SENSITIVE)
1513 {
1514 gboolean sensitive;
1515
1516 DB( g_print(" - UF_SENSITIVE\n") );
1517
1518 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope));
1519 count = gtk_tree_selection_count_selected_rows(selection);
1520 DB( g_print(" - count = %d\n", count) );
1521
1522 //showall part
1523 sensitive = !data->showall;
1524 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/AccountMenu/ExportPDF"), sensitive);
1525 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/AccountMenu/ExportQIF"), sensitive);
1526 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/AccountMenu/ExportCSV"), sensitive);
1527 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/ChkIntXfer"), sensitive);
1528 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/DuplicateMark"), sensitive);
1529 //gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/DuplicateClear"), sensitive);
1530
1531 //5.3.1 if closed account : disable any change
1532 sensitive = TRUE;
1533 if( (data->showall == FALSE) && (data->acc->flags & AF_CLOSED) )
1534 sensitive = FALSE;
1535
1536 gtk_widget_set_sensitive (data->TB_bar, sensitive);
1537 //gtk_widget_set_sensitive (data->TB_tools, sensitive);
1538 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/ToolBar/Assign"), data->showall ? FALSE : sensitive);
1539
1540 gtk_widget_set_sensitive(gtk_ui_manager_get_widget(data->ui, "/MenuBar/TxnMenu"), sensitive);
1541 gtk_widget_set_sensitive(gtk_ui_manager_get_widget(data->ui, "/MenuBar/ToolsMenu"), sensitive);
1542
1543 // multiple: disable inherit, edit
1544 sensitive = (count != 1 ) ? FALSE : TRUE;
1545 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Inherit"), sensitive);
1546 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Edit"), sensitive);
1547 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Inherit"), sensitive);
1548 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Edit"), sensitive);
1549
1550 // single: disable multiedit
1551 sensitive = (count <= 1 ) ? FALSE : TRUE;
1552 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/MultiEdit"), sensitive);
1553 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/MultiEdit"), sensitive);
1554
1555 // no selection: disable reconcile, delete
1556 sensitive = (count > 0 ) ? TRUE : FALSE;
1557 gtk_widget_set_sensitive(gtk_ui_manager_get_widget(data->ui, "/MenuBar/TxnMenu/TxnStatusMenu"), sensitive);
1558 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Delete"), sensitive);
1559 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Template"), sensitive);
1560 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Delete"), sensitive);
1561 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Cleared"), sensitive);
1562 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Reconciled"), sensitive);
1563 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Template"), sensitive);
1564
1565 // euro convert
1566 sensitive = (data->showall == TRUE) ? FALSE : PREFS->euro_active;
1567 if( (data->acc != NULL) && currency_is_euro(data->acc->kcur) )
1568 sensitive = FALSE;
1569 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/ConvToEuro"), sensitive);
1570
1571 }
1572
1573 /* update toolbar & list */
1574 if(flags & UF_VISUAL)
1575 {
1576 DB( g_print(" - UF_VISUAL\n") );
1577
1578 if(PREFS->toolbar_style == 0)
1579 gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_bar));
1580 else
1581 gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_bar), PREFS->toolbar_style-1);
1582
1583 //minor ?
1584 if( PREFS->euro_active )
1585 {
1586 gtk_widget_show(data->CM_minor);
1587 }
1588 else
1589 {
1590 gtk_widget_hide(data->CM_minor);
1591 }
1592 }
1593
1594 /* update balances */
1595 if(flags & UF_BALANCE)
1596 {
1597 DB( g_print(" - UF_BALANCE\n") );
1598
1599 if(data->showall == FALSE)
1600 {
1601 Account *acc = data->acc;
1602
1603 register_panel_balance_refresh(widget);
1604 hb_label_set_colvalue(GTK_LABEL(data->TX_balance[0]), acc->bal_bank, acc->kcur, GLOBALS->minor);
1605 hb_label_set_colvalue(GTK_LABEL(data->TX_balance[1]), acc->bal_today, acc->kcur, GLOBALS->minor);
1606 hb_label_set_colvalue(GTK_LABEL(data->TX_balance[2]), acc->bal_future, acc->kcur, GLOBALS->minor);
1607 }
1608 else
1609 {
1610 GList *lst_acc, *lnk_acc;
1611 gdouble bank, today, future;
1612
1613 bank = today = future = 0.0;
1614 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
1615 lnk_acc = g_list_first(lst_acc);
1616 while (lnk_acc != NULL)
1617 {
1618 Account *acc = lnk_acc->data;
1619
1620 bank += hb_amount_base(acc->bal_bank, acc->kcur);
1621 today += hb_amount_base(acc->bal_today, acc->kcur);
1622 future += hb_amount_base(acc->bal_future, acc->kcur);
1623
1624 lnk_acc = g_list_next(lnk_acc);
1625 }
1626 g_list_free(lst_acc);
1627
1628 hb_label_set_colvalue(GTK_LABEL(data->TX_balance[0]), bank, GLOBALS->kcur, GLOBALS->minor);
1629 hb_label_set_colvalue(GTK_LABEL(data->TX_balance[1]), today, GLOBALS->kcur, GLOBALS->minor);
1630 hb_label_set_colvalue(GTK_LABEL(data->TX_balance[2]), future, GLOBALS->kcur, GLOBALS->minor);
1631 }
1632 ui_hub_account_populate(GLOBALS->mainwindow, NULL);
1633 }
1634
1635 /* update fltinfo */
1636 DB( g_print(" - statusbar\n") );
1637
1638 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope));
1639 count = gtk_tree_selection_count_selected_rows(selection);
1640 DB( g_print(" - nb selected = %d\n", count) );
1641
1642 /* if more than one ope selected, we make a sum to display to the user */
1643 gdouble opeexp = 0.0;
1644 gdouble opeinc = 0.0;
1645 gchar buf1[64];
1646 gchar buf2[64];
1647 gchar buf3[64];
1648 gchar fbufavg[64];
1649 guint32 kcur;
1650
1651 kcur = (data->showall == TRUE) ? GLOBALS->kcur : data->acc->kcur;
1652
1653
1654 if( count >= 1 )
1655 {
1656 GList *list, *tmplist;
1657 GtkTreeModel *model;
1658 GtkTreeIter iter;
1659
1660 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope));
1661 list = gtk_tree_selection_get_selected_rows(selection, &model);
1662 tmplist = g_list_first(list);
1663 while (tmplist != NULL)
1664 {
1665 Transaction *item;
1666
1667 gtk_tree_model_get_iter(model, &iter, tmplist->data);
1668 gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &item, -1);
1669
1670 if( data->showall == FALSE )
1671 {
1672 if( item->flags & OF_INCOME )
1673 opeinc += item->amount;
1674 else
1675 opeexp += item->amount;
1676 }
1677 else
1678 {
1679 if( item->flags & OF_INCOME )
1680 opeinc += hb_amount_base(item->amount, item->kcur);
1681 else
1682 opeexp += hb_amount_base(item->amount, item->kcur);
1683 }
1684
1685 DB( g_print(" - %s, %.2f\n", item->memo, item->amount ) );
1686
1687 tmplist = g_list_next(tmplist);
1688 }
1689 g_list_free(list);
1690
1691 DB( g_print(" %f - %f = %f\n", opeinc, opeexp, opeinc + opeexp) );
1692
1693
1694 hb_strfmon(buf1, 64-1, opeinc, kcur, GLOBALS->minor);
1695 hb_strfmon(buf2, 64-1, -opeexp, kcur, GLOBALS->minor);
1696 hb_strfmon(buf3, 64-1, opeinc + opeexp, kcur, GLOBALS->minor);
1697 hb_strfmon(fbufavg, 64-1, (opeinc + opeexp) / count, kcur, GLOBALS->minor);
1698 }
1699
1700 gchar *msg;
1701
1702 if( count <= 1 )
1703 {
1704 msg = g_strdup_printf(_("%d transactions"), data->total);
1705 }
1706 else
1707 msg = g_strdup_printf(_("%d transactions, %d selected, avg: %s, sum: %s (%s - %s)"), data->total, count, fbufavg, buf3, buf1, buf2);
1708
1709 gtk_label_set_markup(GTK_LABEL(data->TX_selection), msg);
1710 g_free (msg);
1711
1712 }
1713
1714
1715 void register_panel_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata)
1716 {
1717 struct register_panel_data *data;
1718 GtkTreeModel *model;
1719 GtkTreeIter iter;
1720 gint col_id, count;
1721 Transaction *ope;
1722
1723 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
1724
1725 //5.3.1 if closed account : disable any change
1726 if( (data->showall == FALSE) && (data->acc->flags & AF_CLOSED) )
1727 return;
1728
1729
1730 col_id = gtk_tree_view_column_get_sort_column_id (col);
1731
1732 count = gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(treeview));
1733
1734 model = gtk_tree_view_get_model(treeview);
1735
1736 //get transaction double clicked to initiate the widget
1737 gtk_tree_model_get_iter(model, &iter, path);
1738 gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &ope, -1);
1739
1740
1741 DB( g_print ("%d rows been double-clicked on column=%d! ope=%s\n", count, col_id, ope->memo) );
1742
1743 if( count == 1)
1744 {
1745 register_panel_action(GTK_WIDGET(treeview), GINT_TO_POINTER(ACTION_ACCOUNT_EDIT));
1746 }
1747 else
1748 {
1749 if( data->showall == FALSE )
1750 {
1751 if(col_id >= LST_DSPOPE_DATE && col_id != LST_DSPOPE_BALANCE)
1752 {
1753 register_panel_edit_multiple (data->window, ope, col_id, data);
1754 }
1755 }
1756 }
1757 }
1758
1759
1760 /*
1761 static gint listview_context_cb (GtkWidget *widget, GdkEventButton *event, GtkWidget *menu)
1762 {
1763
1764 if (event->button == 3)
1765 {
1766
1767
1768 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview),
1769 (gint) event->x, (gint) event->y, &path, NULL, NULL, NULL))
1770 {
1771 gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, NULL, FALSE);
1772 gtk_tree_path_free (path);
1773 }
1774
1775
1776
1777
1778 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
1779 event->button, event->time);
1780
1781 // On indique à l'appelant que l'on a géré cet événement.
1782
1783 return TRUE;
1784 }
1785
1786 // On indique à l'appelant que l'on n'a pas géré cet événement.
1787
1788 return FALSE;
1789 }
1790 */
1791
1792
1793 /*
1794 ** populate the account window
1795 */
1796 void register_panel_window_init(GtkWidget *widget, gpointer user_data)
1797 {
1798 struct register_panel_data *data;
1799
1800 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1801
1802 DB( g_print("\n[account] init window\n") );
1803
1804 if( data->showall == TRUE )
1805 {
1806 gtk_label_set_text (GTK_LABEL(data->LB_name), _("All transactions"));
1807 hb_widget_visible (data->IM_closed, FALSE);
1808 }
1809 else
1810 {
1811 gtk_label_set_text (GTK_LABEL(data->LB_name), data->acc->name);
1812 hb_widget_visible (data->IM_closed, (data->acc->flags & AF_CLOSED) ? TRUE : FALSE);
1813
1814 DB( g_print(" - sort transactions\n") );
1815 da_transaction_queue_sort(data->acc->txn_queue);
1816 }
1817
1818 list_txn_set_column_acc_visible(GTK_TREE_VIEW(data->LV_ope), data->showall);
1819
1820 //DB( g_print(" mindate=%d, maxdate=%d %x\n", data->filter->mindate,data->filter->maxdate) );
1821
1822 DB( g_print(" - call update visual\n") );
1823 register_panel_update(widget, GINT_TO_POINTER(UF_VISUAL|UF_SENSITIVE));
1824
1825 DB( g_print(" - set range or populate+update sensitive+balance\n") );
1826
1827 register_panel_cb_filter_reset(widget, user_data);
1828
1829 }
1830
1831 /*
1832 **
1833 */
1834 static gboolean
1835 register_panel_getgeometry(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data)
1836 {
1837 //struct register_panel_data *data = user_data;
1838 struct WinGeometry *wg;
1839
1840 DB( g_print("\n[account] get geometry\n") );
1841
1842 //store position and size
1843 wg = &PREFS->acc_wg;
1844 gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t);
1845 gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h);
1846 GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(widget));
1847 GdkWindowState state = gdk_window_get_state(gdk_window);
1848 wg->s = (state & GDK_WINDOW_STATE_MAXIMIZED) ? 1 : 0;
1849
1850 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d s=%d, state=%d\n", wg->l, wg->t, wg->w, wg->h, wg->s, state & GDK_WINDOW_STATE_MAXIMIZED) );
1851
1852 return FALSE;
1853 }
1854
1855 /*
1856 **
1857 */
1858 static gboolean register_panel_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1859 {
1860 struct register_panel_data *data = user_data;
1861
1862 data = g_object_get_data(G_OBJECT(widget), "inst_data");
1863
1864 DB( g_print("\n[account] delete-event\n") );
1865
1866 register_panel_getgeometry(data->window, NULL, data);
1867
1868 return FALSE;
1869 }
1870
1871 /* Another callback */
1872 static gboolean register_panel_destroy( GtkWidget *widget,
1873 gpointer user_data )
1874 {
1875 struct register_panel_data *data;
1876
1877 data = g_object_get_data(G_OBJECT(widget), "inst_data");
1878
1879
1880 DB( g_print ("\n[account] destroy event occurred\n") );
1881
1882
1883
1884 //enable define windows
1885 GLOBALS->define_off--;
1886
1887 /* unset transaction edit mutex */
1888 if(data->showall == FALSE)
1889 data->acc->window = NULL;
1890 else
1891 GLOBALS->alltxnwindow = NULL;
1892
1893 /* free title and filter */
1894 DB( g_print(" user_data=%p to be free\n", user_data) );
1895 g_free(data->wintitle);
1896
1897 if(data->gpatxn != NULL)
1898 g_ptr_array_free (data->gpatxn, TRUE);
1899
1900 da_flt_free(data->filter);
1901
1902 g_free(data);
1903
1904
1905 //our global list has changed, so update the treeview
1906 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL));
1907
1908 return FALSE;
1909 }
1910
1911
1912 static void quick_search_text_changed_cb (GtkWidget *widget, gpointer user_data)
1913 {
1914 struct register_panel_data *data = user_data;
1915
1916 register_panel_listview_populate (data->window);
1917 }
1918
1919
1920 static GtkActionEntry entries[] = {
1921
1922 /* name, icon-name, label */
1923 { "AccountMenu" , NULL, N_("A_ccount"), NULL, NULL, NULL },
1924 { "TxnMenu" , NULL, N_("Transacti_on"), NULL, NULL, NULL },
1925 { "TxnStatusMenu", NULL, N_("_Status"), NULL, NULL, NULL },
1926 { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL },
1927
1928
1929 /* name, icon-name, label, accelerator, tooltip */
1930 { "ExportPDF" , NULL , N_("Export as PDF..."), NULL, N_("Export to a PDF file"), G_CALLBACK (register_panel_action_exportpdf) },
1931 { "ExportQIF" , NULL , N_("Export QIF..."), NULL, N_("Export as QIF"), G_CALLBACK (register_panel_action_exportqif) },
1932 { "ExportCSV" , NULL , N_("Export CSV..."), NULL, N_("Export as CSV"), G_CALLBACK (register_panel_action_exportcsv) },
1933 { "Close" , ICONNAME_CLOSE , N_("_Close") , "<control>W", N_("Close the current account"), G_CALLBACK (register_panel_action_close) },
1934
1935 { "Add" , ICONNAME_HB_OPE_ADD , N_("_Add..."), NULL, N_("Add a new transaction"), G_CALLBACK (register_panel_action_add) },
1936 { "Inherit" , ICONNAME_HB_OPE_HERIT , N_("_Inherit..."), NULL, N_("Inherit from the active transaction"), G_CALLBACK (register_panel_action_inherit) },
1937 { "Edit" , ICONNAME_HB_OPE_EDIT , N_("_Edit..."), NULL, N_("Edit the active transaction"), G_CALLBACK (register_panel_action_edit) },
1938
1939 { "None" , NULL , N_("_None"), "<control>N", N_("Toggle none for selected transaction(s)"), G_CALLBACK (register_panel_action_none) },
1940 { "Cleared" , ICONNAME_HB_OPE_CLEARED , N_("_Cleared"), "<control>C", N_("Toggle cleared for selected transaction(s)"), G_CALLBACK (register_panel_action_clear) },
1941 { "Reconciled" , ICONNAME_HB_OPE_RECONCILED, N_("_Reconciled"), "<control>R", N_("Toggle reconciled for selected transaction(s)"), G_CALLBACK (register_panel_action_reconcile) },
1942
1943 { "MultiEdit" , ICONNAME_HB_OPE_MULTIEDIT , N_("_Multiple Edit..."), NULL, N_("Edit multiple transaction"), G_CALLBACK (register_panel_action_multiedit) },
1944 { "Template" , ICONNAME_CONVERT , N_("Create template..."), NULL, N_("Create template"), G_CALLBACK (register_panel_action_createtemplate) },
1945 { "Delete" , ICONNAME_HB_OPE_DELETE , N_("_Delete..."), NULL, N_("Delete selected transaction(s)"), G_CALLBACK (register_panel_action_remove) },
1946
1947 { "DuplicateMark", NULL , N_("Mark duplicate..."), NULL, NULL, G_CALLBACK (register_panel_action_duplicate_mark) },
1948 // { "DuplicateClear", NULL , N_("Unmark duplicate"), NULL, NULL, G_CALLBACK (register_panel_action_duplicate_unmark) },
1949
1950 { "ChkIntXfer" , NULL , N_("Check internal xfer"), NULL, NULL, G_CALLBACK (register_panel_action_check_internal_xfer) },
1951 { "Assign" , ICONNAME_HB_ASSIGN_RUN , N_("Auto. assignments"), NULL, N_("Run automatic assignments"), G_CALLBACK (register_panel_action_assign) },
1952
1953 { "Filter" , ICONNAME_HB_FILTER , N_("_Filter..."), NULL, N_("Open the list filter"), G_CALLBACK (register_panel_action_editfilter) },
1954 { "ConvToEuro" , NULL , N_("Convert to Euro..."), NULL, N_("Convert this account to Euro currency"), G_CALLBACK (register_panel_action_converttoeuro) },
1955
1956 };
1957 static guint n_entries = G_N_ELEMENTS (entries);
1958
1959
1960 static const gchar *ui_info =
1961 "<ui>"
1962 "<menubar name='MenuBar'>"
1963 " <menu action='AccountMenu'>"
1964 " <menuitem action='ExportQIF'/>"
1965 " <menuitem action='ExportCSV'/>"
1966 " <separator/>"
1967 " <menuitem action='ExportPDF'/>"
1968 " <separator/>"
1969 " <menuitem action='Close'/>"
1970 " </menu>"
1971 " <menu action='TxnMenu'>"
1972 " <menuitem action='Add'/>"
1973 " <menuitem action='Inherit'/>"
1974 " <menuitem action='Edit'/>"
1975 " <separator/>"
1976 " <menu action='TxnStatusMenu'>"
1977 " <menuitem action='None'/>"
1978 " <menuitem action='Cleared'/>"
1979 " <menuitem action='Reconciled'/>"
1980 " </menu>"
1981 " <separator/>"
1982 " <menuitem action='MultiEdit'/>"
1983 " <menuitem action='Template'/>"
1984 " <menuitem action='Delete'/>"
1985 " </menu>"
1986 " <menu action='ToolsMenu'>"
1987 " <menuitem action='DuplicateMark'/>"
1988 //" <menuitem action='DuplicateClear'/>"
1989 " <separator/>"
1990 " <menuitem action='ChkIntXfer'/>"
1991 " <separator/>"
1992 " <menuitem action='Filter'/>"
1993 " <menuitem action='Assign'/>"
1994 " <separator/>"
1995 " <menuitem action='ConvToEuro'/>"
1996 " </menu>"
1997 "</menubar>"
1998
1999 "<toolbar name='TxnBar'>"
2000 " <toolitem action='Add'/>"
2001 " <toolitem action='Inherit'/>"
2002 " <toolitem action='Edit'/>"
2003 " <separator/>"
2004 " <toolitem action='Cleared'/>"
2005 " <toolitem action='Reconciled'/>"
2006 " <separator/>"
2007 " <toolitem action='MultiEdit'/>"
2008 " <toolitem action='Template'/>"
2009 " <toolitem action='Delete'/>"
2010 "</toolbar>"
2011 "<toolbar name='ToolBar'>"
2012 " <toolitem action='Filter'/>"
2013 " <toolitem action='Assign'/>"
2014 "</toolbar>"
2015 "</ui>";
2016
2017
2018 /*
2019 * if accnum = 0 or acc is null : show all account
2020 */
2021 GtkWidget *register_panel_window_new(Account *acc)
2022 {
2023 struct register_panel_data *data;
2024 struct WinGeometry *wg;
2025 GtkWidget *window, *mainbox, *table, *sw, *bar;
2026 GtkWidget *treeview, *label, *widget, *image;
2027 //GtkWidget *menu, *menu_items;
2028 GtkUIManager *ui;
2029 GtkActionGroup *actions;
2030 GtkAction *action;
2031 GError *error = NULL;
2032
2033 DB( g_print("\n[account] create_register_panel_window\n") );
2034
2035 data = g_malloc0(sizeof(struct register_panel_data));
2036 if(!data) return NULL;
2037
2038 //disable define windows
2039 GLOBALS->define_off++;
2040 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE));
2041
2042 /* create window, etc */
2043 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2044 data->window = window;
2045
2046 //store our window private data
2047 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data);
2048 DB( g_print(" - new window=%p, inst_data=%p\n", window, data) );
2049
2050 data->acc = acc;
2051 data->showall = (acc != NULL) ? FALSE : TRUE;
2052
2053 if(data->showall == FALSE)
2054 {
2055 data->acc->window = GTK_WINDOW(window);
2056 if( data->acc->flags & AF_CLOSED )
2057 data->wintitle = g_strdup_printf("%s %s - HomeBank", data->acc->name, _("(closed)"));
2058 else
2059 data->wintitle = g_strdup_printf("%s - HomeBank", data->acc->name);
2060 }
2061 else
2062 {
2063 GLOBALS->alltxnwindow = window;
2064 data->wintitle = g_strdup_printf(_("%s - HomeBank"), _("All transactions"));
2065 }
2066
2067 gtk_window_set_title (GTK_WINDOW (window), data->wintitle);
2068 gtk_window_set_icon_name(GTK_WINDOW (window), ICONNAME_HB_OPE_SHOW );
2069
2070 // connect our dispose function
2071 g_signal_connect (window, "delete-event",
2072 G_CALLBACK (register_panel_dispose), (gpointer)data);
2073
2074 // connect our dispose function
2075 g_signal_connect (window, "destroy",
2076 G_CALLBACK (register_panel_destroy), (gpointer)data);
2077
2078 // connect our dispose function
2079 //g_signal_connect (window, "configure-event",
2080 // G_CALLBACK (register_panel_getgeometry), (gpointer)data);
2081
2082 #if UI == 1
2083 //start test uimanager
2084
2085 actions = gtk_action_group_new ("Account");
2086
2087 //as we use gettext
2088 gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE);
2089
2090
2091 DB( g_print(" - add actions: %p user_data: %p\n", actions, data) );
2092 gtk_action_group_add_actions (actions, entries, n_entries, data);
2093
2094 /* set which action should have priority in the toolbar */
2095 action = gtk_action_group_get_action(actions, "Add");
2096 g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL);
2097
2098 action = gtk_action_group_get_action(actions, "Inherit");
2099 g_object_set(action, "is_important", TRUE, "short_label", _("Inherit"), NULL);
2100
2101 action = gtk_action_group_get_action(actions, "Edit");
2102 g_object_set(action, "is_important", TRUE, "short_label", _("Edit"), NULL);
2103
2104 action = gtk_action_group_get_action(actions, "Filter");
2105 g_object_set(action, "is_important", TRUE, "short_label", _("Filter"), NULL);
2106
2107 //action = gtk_action_group_get_action(actions, "Reconciled");
2108 //g_object_set(action, "is_important", TRUE, "short_label", _("Reconciled"), NULL);
2109
2110
2111 ui = gtk_ui_manager_new ();
2112
2113 DB( g_print(" - insert action group:\n") );
2114 gtk_ui_manager_insert_action_group (ui, actions, 0);
2115
2116 GtkAccelGroup *ag = gtk_ui_manager_get_accel_group (ui);
2117
2118 DB( g_print(" - add_accel_group actions=%p, ui=%p, ag=%p\n", actions, ui, ag) );
2119
2120 gtk_window_add_accel_group (GTK_WINDOW (window), ag);
2121
2122 DB( g_print(" - add ui from string:\n") );
2123 if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error))
2124 {
2125 g_message ("building menus failed: %s", error->message);
2126 g_error_free (error);
2127 }
2128
2129 data->ui = ui;
2130 data->actions = actions;
2131 #endif
2132
2133 mainbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2134 //gtk_container_set_border_width(GTK_CONTAINER(mainbox), SPACING_SMALL);
2135 gtk_container_add (GTK_CONTAINER (window), mainbox);
2136
2137 widget = gtk_ui_manager_get_widget (ui, "/MenuBar");
2138 //data->menu = widget;
2139 gtk_box_pack_start (GTK_BOX (mainbox), widget, FALSE, FALSE, 0);
2140
2141 // info bar for duplicate
2142 bar = gtk_info_bar_new_with_buttons (_("_Refresh"), HB_RESPONSE_REFRESH, NULL);
2143 data->IB_duplicate = bar;
2144 gtk_box_pack_start (GTK_BOX (mainbox), bar, FALSE, FALSE, 0);
2145
2146 gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING);
2147 gtk_info_bar_set_show_close_button (GTK_INFO_BAR (bar), TRUE);
2148 label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_WARNING");
2149 data->LB_duplicate = label;
2150 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
2151 gtk_label_set_xalign (GTK_LABEL (label), 0);
2152 gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0);
2153
2154 widget = make_numeric(NULL, 0, HB_DATE_MAX_GAP);
2155 data->NB_txn_daygap = widget;
2156 gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), widget, FALSE, FALSE, 0);
2157
2158 table = gtk_grid_new();
2159 gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL);
2160 gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM);
2161 gtk_container_set_border_width (GTK_CONTAINER(table), SPACING_SMALL);
2162 gtk_box_pack_start (GTK_BOX (mainbox), table, FALSE, FALSE, 0);
2163
2164 // account name (+ balance)
2165 widget = gtk_image_new_from_icon_name (ICONNAME_CHANGES_PREVENT, GTK_ICON_SIZE_BUTTON);
2166 data->IM_closed = widget;
2167 gtk_grid_attach (GTK_GRID(table), widget, 0, 0, 1, 1);
2168
2169 label = gtk_label_new(NULL);
2170 data->LB_name = label;
2171 gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_LARGE, -1);
2172 gtk_widget_set_halign (label, GTK_ALIGN_START);
2173 gtk_widget_set_hexpand (label, TRUE);
2174 gtk_grid_attach (GTK_GRID(table), label, 1, 0, 1, 1);
2175
2176 /* balances area */
2177 label = gtk_label_new(_("Bank:"));
2178 gtk_grid_attach (GTK_GRID(table), label, 3, 0, 1, 1);
2179 widget = gtk_label_new(NULL);
2180 data->TX_balance[0] = widget;
2181 gtk_grid_attach (GTK_GRID(table), widget, 4, 0, 1, 1);
2182
2183 label = gtk_label_new(_("Today:"));
2184 gtk_grid_attach (GTK_GRID(table), label, 5, 0, 1, 1);
2185 widget = gtk_label_new(NULL);
2186 data->TX_balance[1] = widget;
2187 gtk_grid_attach (GTK_GRID(table), widget, 6, 0, 1, 1);
2188
2189 label = gtk_label_new(_("Future:"));
2190 gtk_grid_attach (GTK_GRID(table), label, 7, 0, 1, 1);
2191
2192 widget = gtk_label_new(NULL);
2193 data->TX_balance[2] = widget;
2194 gtk_grid_attach (GTK_GRID(table), widget, 8, 0, 1, 1);
2195
2196 //quick search
2197 widget = make_search ();
2198 data->ST_search = widget;
2199 gtk_widget_set_size_request(widget, HB_MINWIDTH_SEARCH, -1);
2200 gtk_grid_attach (GTK_GRID(table), widget, 9, 0, 1, 1);
2201
2202 data->handler_id[HID_SEARCH] = g_signal_connect (data->ST_search, "search-changed", G_CALLBACK (quick_search_text_changed_cb), data);
2203
2204
2205 // windows interior
2206 table = gtk_grid_new();
2207 gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL);
2208 gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM);
2209 gtk_container_set_border_width (GTK_CONTAINER(table), SPACING_SMALL);
2210 gtk_box_pack_start (GTK_BOX (mainbox), table, FALSE, FALSE, 0);
2211
2212 label = make_label_widget(_("_Range:"));
2213 gtk_grid_attach (GTK_GRID(table), label, 0, 0, 1, 1);
2214 data->CY_range = make_daterange(label, DATE_RANGE_CUSTOM_SHOW);
2215 gtk_grid_attach (GTK_GRID(table), data->CY_range, 1, 0, 1, 1);
2216
2217 widget = gtk_toggle_button_new();
2218 image = gtk_image_new_from_icon_name (ICONNAME_HB_OPE_FUTURE, GTK_ICON_SIZE_MENU);
2219 g_object_set (widget, "image", image, NULL);
2220 gtk_widget_set_tooltip_text (widget, _("Toggle show future transaction"));
2221 data->CM_future = widget;
2222 gtk_grid_attach (GTK_GRID(table), widget, 2, 0, 1, 1);
2223
2224 label = make_label_widget(_("_Type:"));
2225 gtk_grid_attach (GTK_GRID(table), label, 3, 0, 1, 1);
2226 data->CY_type = make_cycle(label, CYA_FLT_TYPE);
2227 gtk_grid_attach (GTK_GRID(table), data->CY_type, 4, 0, 1, 1);
2228
2229 label = make_label_widget(_("_Status:"));
2230 gtk_grid_attach (GTK_GRID(table), label, 5, 0, 1, 1);
2231 data->CY_status = make_cycle(label, CYA_FLT_STATUS);
2232 gtk_grid_attach (GTK_GRID(table), data->CY_status, 6, 0, 1, 1);
2233
2234 //widget = gtk_button_new_with_mnemonic (_("Reset _filters"));
2235 widget = gtk_button_new_with_mnemonic (_("_Reset"));
2236 data->BT_reset = widget;
2237 gtk_grid_attach (GTK_GRID(table), widget, 7, 0, 1, 1);
2238
2239 //TRANSLATORS: this is for Euro specific users, a toggle to display in 'Minor' currency
2240 widget = gtk_check_button_new_with_mnemonic (_("Euro _minor"));
2241 data->CM_minor = widget;
2242 gtk_grid_attach (GTK_GRID(table), widget, 8, 0, 1, 1);
2243
2244 label = make_label(NULL, 0.0, 0.5);
2245 data->TX_selection = label;
2246 gtk_widget_set_halign (label, GTK_ALIGN_END);
2247 gtk_widget_set_hexpand (label, TRUE);
2248 gtk_grid_attach (GTK_GRID(table), label, 10, 0, 1, 1);
2249
2250 /*
2251 label = make_label_widget(_("_Month:"));
2252 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
2253 data->CY_month = make_cycle(label, CYA_SELECT);
2254 gtk_box_pack_start (GTK_BOX (hbox), data->CY_month, FALSE, FALSE, 0);
2255
2256 label = make_label_widget(_("_Year:"),);
2257 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
2258 data->NB_year = make_year(label);
2259 gtk_box_pack_start (GTK_BOX (hbox), data->NB_year, FALSE, FALSE, 0);
2260 */
2261
2262 //list
2263 sw = gtk_scrolled_window_new (NULL, NULL);
2264 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
2265 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2266 treeview = (GtkWidget *)create_list_transaction(LIST_TXN_TYPE_BOOK, PREFS->lst_ope_columns);
2267 data->LV_ope = treeview;
2268 gtk_container_add (GTK_CONTAINER (sw), treeview);
2269 gtk_box_pack_start (GTK_BOX (mainbox), sw, TRUE, TRUE, 0);
2270
2271 list_txn_set_save_column_width(GTK_TREE_VIEW(treeview), TRUE);
2272
2273 /* toolbars */
2274 table = gtk_grid_new();
2275 gtk_box_pack_start (GTK_BOX (mainbox), table, FALSE, FALSE, 0);
2276
2277 widget = gtk_ui_manager_get_widget (ui, "/TxnBar");
2278 data->TB_bar = widget;
2279 //gtk_widget_set_halign (widget, GTK_ALIGN_START);
2280 //gtk_style_context_add_class (gtk_widget_get_style_context (widget), GTK_STYLE_CLASS_INLINE_TOOLBAR);
2281 gtk_widget_set_hexpand (widget, TRUE);
2282 gtk_grid_attach (GTK_GRID(table), widget, 0, 0, 1, 1);
2283
2284 widget = gtk_ui_manager_get_widget (ui, "/ToolBar");
2285 data->TB_tools = widget;
2286 //gtk_widget_set_halign (widget, GTK_ALIGN_END);
2287 //gtk_style_context_add_class (gtk_widget_get_style_context (widget), GTK_STYLE_CLASS_INLINE_TOOLBAR);
2288 gtk_widget_set_hexpand (widget, TRUE);
2289 gtk_grid_attach (GTK_GRID(table), widget, 2, 0, 1, 1);
2290
2291 #ifdef G_OS_WIN32
2292 if(PREFS->toolbar_style == 0)
2293 {
2294 gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_bar));
2295 gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_tools));
2296 }
2297 else
2298 {
2299 gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_bar), PREFS->toolbar_style-1);
2300 gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_tools), PREFS->toolbar_style-1);
2301 }
2302 #endif
2303
2304 //todo: should move this
2305 //setup
2306 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope))), "minor", data->CM_minor);
2307 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_future), (PREFS->date_future_nbdays > 0) ? TRUE : FALSE );
2308 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_minor), GLOBALS->minor);
2309 gtk_widget_grab_focus(GTK_WIDGET(data->LV_ope));
2310
2311 // connect signals
2312 g_signal_connect (data->IB_duplicate , "response", G_CALLBACK (register_panel_cb_bar_duplicate_response), NULL);
2313
2314 data->handler_id[HID_RANGE] = g_signal_connect (data->CY_range , "changed", G_CALLBACK (register_panel_cb_filter_daterange), NULL);
2315 data->handler_id[HID_TYPE] = g_signal_connect (data->CY_type , "changed", G_CALLBACK (register_panel_cb_filter_type), NULL);
2316 data->handler_id[HID_STATUS] = g_signal_connect (data->CY_status, "changed", G_CALLBACK (register_panel_cb_filter_status), NULL);
2317
2318 g_signal_connect (data->CM_future, "toggled", G_CALLBACK (register_panel_cb_filter_daterange), NULL);
2319
2320 g_signal_connect (data->BT_reset , "clicked", G_CALLBACK (register_panel_cb_filter_reset), NULL);
2321
2322 g_signal_connect (data->CM_minor , "toggled", G_CALLBACK (register_panel_toggle_minor), NULL);
2323
2324 //g_signal_connect (GTK_TREE_VIEW(treeview), "cursor-changed", G_CALLBACK (register_panel_update), (gpointer)2);
2325 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", G_CALLBACK (register_panel_selection), NULL);
2326 g_signal_connect (GTK_TREE_VIEW(treeview), "row-activated", G_CALLBACK (register_panel_onRowActivated), GINT_TO_POINTER(2));
2327
2328
2329 //todo: test context menu
2330 /*
2331 menu = gtk_menu_new();
2332 menu_items = gtk_ui_manager_get_widget (ui, "/MenuBar/TxnMenu/Add");
2333
2334 menu_items = gtk_menu_item_new_with_label ("test");
2335 gtk_widget_show(menu_items);
2336 gtk_menu_shell_append (GTK_MENU (menu), menu_items);
2337
2338 //todo: debug test
2339 g_signal_connect (treeview, "button-press-event", G_CALLBACK (listview_context_cb),
2340 // todo: here is not a GtkMenu but GtkImageMenuItem...
2341 menu
2342 //gtk_ui_manager_get_widget (ui, "/MenuBar")
2343 );
2344 */
2345
2346 //setup, init and show window
2347 wg = &PREFS->acc_wg;
2348 if(wg->s == 0)
2349 {
2350 gtk_window_move(GTK_WINDOW(window), wg->l, wg->t);
2351 gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h);
2352 }
2353 else
2354 gtk_window_maximize(GTK_WINDOW(window));
2355
2356 gtk_widget_show_all (window);
2357 gtk_widget_hide(data->IB_duplicate);
2358
2359 /* hide showfuture */
2360 hb_widget_visible (data->CM_future, PREFS->date_future_nbdays > 0 ? TRUE : FALSE);
2361
2362
2363 /* make sure splash is up */
2364 while (gtk_events_pending ())
2365 gtk_main_iteration ();
2366
2367 /* setup to moove later */
2368 data->filter = da_flt_malloc();
2369 DB( g_print(" - filter ok %p\n", data->filter) );
2370
2371
2372 return window;
2373 }
This page took 0.152051 seconds and 4 git commands to generate.