34 #include <glib/gi18n.h> 35 #ifdef __G_IR_SCANNER__ 36 #undef __G_IR_SCANNER__ 38 #include <gdk/gdkkeysyms.h> 46 #include "dialog-transfer.h" 47 #include "dialog-utils.h" 48 #include "gnc-amount-edit.h" 49 #include "gnc-autoclear.h" 50 #include "gnc-component-manager.h" 52 #include "gnc-date-edit.h" 61 #include "gnc-ui-balances.h" 63 #include "reconcile-view.h" 64 #include "window-reconcile.h" 65 #include "gnc-session.h" 66 #ifdef MAC_INTEGRATION 67 #include <gtkmacintegration/gtkosxapplication.h> 70 #define WINDOW_RECONCILE_CM_CLASS "window-reconcile" 71 #define GNC_PREF_AUTO_CC_PAYMENT "auto-cc-payment" 72 #define GNC_PREF_ALWAYS_REC_TO_TODAY "always-reconcile-to-today" 79 gnc_numeric new_ending;
87 GSimpleActionGroup *simple_action_group;
88 GtkWidget *autoclear_button;
89 GtkAccelGroup *accel_group;
93 SplitsVec autoclear_splits;
94 SplitsVec initially_cleared_splits;
99 GtkWidget *reconciled;
100 GtkWidget *difference;
102 GtkWidget *total_debit;
103 GtkWidget *total_credit;
108 GtkWidget *debit_frame;
109 GtkWidget *credit_frame;
111 gboolean delete_refresh;
120 typedef struct _startRecnWindowData
125 GtkWidget *startRecnWindow;
126 GtkWidget *xfer_button;
127 GtkWidget *date_value;
128 GtkWidget *future_icon;
129 GtkWidget *future_text;
130 GNCAmountEdit *end_value;
131 gnc_numeric original_value;
132 gboolean user_set_value;
134 XferDialog *xferData;
135 gboolean include_children;
141 static gnc_numeric recnRecalculateBalance (RecnWindow *recnData);
143 static void recn_destroy_cb (GtkWidget *w, gpointer data);
144 static void recn_cancel (RecnWindow *recnData);
145 static gboolean recn_delete_cb (GtkWidget *widget, GdkEvent *event, gpointer data);
146 static gboolean recn_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data);
147 static void recnAutoClearCB (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
148 static void recnFinishCB (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
149 static void recnPostponeCB (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
150 static void recnCancelCB (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
157 static void gnc_reconcile_window_set_sensitivity (RecnWindow *recnData);
158 static char * gnc_recn_make_window_name (
Account *account);
159 static void gnc_recn_set_window_name (RecnWindow *recnData);
160 static gboolean find_by_account (gpointer
find_data, gpointer user_data);
164 G_GNUC_UNUSED
static QofLogModule log_module = GNC_MOD_GUI;
166 static time64 gnc_reconcile_last_statement_date = 0;
171 commodity_compare(
Account *account, gpointer user_data) {
173 (gnc_commodity*) user_data);
175 return equal ? NULL : account;
187 has_account_different_commodities(
const Account *account)
189 gnc_commodity *parent_commodity;
201 return result != NULL;
205 get_autoclear_icon (GError* error)
207 static std::unordered_map<gint,const char*> icon_names =
209 { Autoclear::ABORT_NONE,
"media-playback-start" },
210 { Autoclear::ABORT_NOP,
"media-playback-stop" },
211 { Autoclear::ABORT_MULTI,
"dialog-information" },
212 { Autoclear::ABORT_TIMEOUT,
"dialog-error" },
213 { Autoclear::ABORT_UNREACHABLE,
"dialog-error" },
215 auto it = icon_names.find (error ? error->code : Autoclear::ABORT_NONE);
216 return it == icon_names.end() ?
"dialog-information" : it->second;
219 #define GNC_PREF_ENABLE_AUTOCLEAR "enable-autoclear-in-reconcile" 222 calculate_autoclear (RecnWindow *recnData)
224 g_return_if_fail (recnData);
226 bool enabled =
gnc_prefs_get_bool (GNC_PREFS_GROUP_RECONCILE, GNC_PREF_ENABLE_AUTOCLEAR);
227 auto action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
228 "RecnAutoClearAction");
229 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), enabled);
230 gtk_widget_set_visible (recnData->autoclear_button, enabled);
234 GError* error =
nullptr;
237 static const unsigned int MAX_AUTOCLEAR_SECONDS = 1;
239 GList *splits_to_clear = gnc_account_get_autoclear_splits
240 (acct, recnData->new_ending, recnData->statement_date, &error, MAX_AUTOCLEAR_SECONDS);
242 gtk_widget_set_sensitive (recnData->autoclear_button, error ==
nullptr);
244 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (recnData->autoclear_button),
245 get_autoclear_icon (error));
247 recnData->autoclear_splits = recnData->initially_cleared_splits;
248 for (
auto n = splits_to_clear; n; n = n->next)
249 recnData->autoclear_splits.push_back (GNC_SPLIT (n->data));
253 gtk_widget_set_tooltip_text (recnData->autoclear_button, _(error->message));
254 g_error_free (error);
258 auto num_splits = g_list_length (splits_to_clear);
261 char* tooltip = g_strdup_printf
262 (ngettext(
"Automatically select %u transaction up to %s that clears to %s",
263 "Automatically select %u transactions up to %s that clear to %s",
265 num_splits, date_buff,
266 xaccPrintAmount (recnData->new_ending, gnc_account_print_info (acct,
true)));
267 gtk_widget_set_tooltip_text (recnData->autoclear_button, tooltip);
270 g_list_free (splits_to_clear);
281 recnRefresh (RecnWindow *recnData)
283 if (recnData == NULL)
286 gnc_reconcile_view_refresh(GNC_RECONCILE_VIEW(recnData->debit));
287 gnc_reconcile_view_refresh(GNC_RECONCILE_VIEW(recnData->credit));
289 gnc_reconcile_window_set_sensitivity(recnData);
291 gnc_recn_set_window_name(recnData);
293 recnRecalculateBalance(recnData);
295 gtk_widget_queue_resize(recnData->window);
300 recn_get_account (RecnWindow *recnData)
310 gnc_add_colorized_amount (gpointer obj, gnc_numeric amt,
315 gnc_set_label_color (GTK_WIDGET (obj), amt);
316 gtk_label_set_text (GTK_LABEL (obj),
xaccPrintAmount (amt, print_info));
328 recnRecalculateBalance (RecnWindow *recnData)
333 gnc_numeric starting;
335 gnc_numeric reconciled;
339 gboolean reverse_balance, include_children;
342 account = recn_get_account (recnData);
344 return gnc_numeric_zero ();
346 reverse_balance = gnc_reverse_balance(account);
348 starting = gnc_ui_account_get_reconciled_balance(account, include_children);
349 print_info = gnc_account_print_info (account, TRUE);
351 ending = recnData->new_ending;
352 debit = gnc_reconcile_view_reconciled_balance
353 (GNC_RECONCILE_VIEW(recnData->debit));
354 credit = gnc_reconcile_view_reconciled_balance
355 (GNC_RECONCILE_VIEW(recnData->credit));
357 reconciled = gnc_numeric_sub_fixed (debit, credit);
359 reconciled = gnc_numeric_sub_fixed (reconciled, starting);
361 reconciled = gnc_numeric_add_fixed (reconciled, starting);
363 diff = gnc_numeric_sub_fixed (ending, reconciled);
366 gtk_label_set_text (GTK_LABEL(recnData->recn_date), datestr);
369 gnc_add_colorized_amount (recnData->starting, starting, print_info, FALSE);
370 gnc_add_colorized_amount (recnData->ending, ending, print_info, reverse_balance);
371 gnc_add_colorized_amount (recnData->total_debit, debit, print_info, FALSE);
372 gnc_add_colorized_amount (recnData->total_credit, credit, print_info, FALSE);
373 gnc_add_colorized_amount (recnData->reconciled, reconciled, print_info, reverse_balance);
374 gnc_add_colorized_amount (recnData->difference, diff, print_info, reverse_balance);
376 action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
380 action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
381 "TransBalanceAction");
384 calculate_autoclear (recnData);
404 gint result = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(data->end_value),
407 data->user_set_value = FALSE;
413 gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(data->end_value), value);
414 gnc_amount_edit_select_region (GNC_AMOUNT_EDIT(data->end_value), 0, -1);
430 amount_edit_focus_out_cb(GtkWidget *widget, GdkEventFocus *event,
433 amount_edit_cb(widget, data);
453 gnc_numeric new_balance;
456 gboolean show_warning = FALSE;
457 gint days_after_today;
458 static const time64 secs_per_day = 86400;
459 static const time64 secs_per_hour = 3600;
461 new_date = gnc_date_edit_get_date_end (gde);
468 secs_per_hour) / secs_per_day;
470 if (days_after_today > 0)
472 gchar *str = g_strdup_printf
474 (ngettext (
"Statement Date is %d day after today.",
475 "Statement Date is %d days after today.",
479 gchar *tip_start = g_strdup_printf
481 (ngettext (
"The statement date you have chosen is %d day in the future.",
482 "The statement date you have chosen is %d days in the future.",
486 gchar *tip_end = g_strdup (_(
"This may cause issues for future reconciliation \ 487 actions on this account. Please double-check this is the date you intended."));
488 gchar *tip = g_strdup_printf (
"%s %s", tip_start, tip_end);
492 gtk_label_set_text (GTK_LABEL(data->future_text), str);
493 gtk_widget_set_tooltip_text (GTK_WIDGET(data->future_text), tip);
499 gtk_widget_set_visible (GTK_WIDGET(data->future_icon), show_warning);
500 gtk_widget_set_visible (GTK_WIDGET(data->future_text), show_warning);
502 if (data->user_set_value)
506 new_balance = gnc_ui_account_get_balance_as_of_date (data->account, new_date,
507 data->include_children);
509 gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (data->end_value),
517 data->include_children =
518 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
521 recn_date_changed_cb (data->date_value, data);
544 gnc_recn_make_interest_window_name(
Account *account,
char *text)
550 title = g_strconcat(fullname,
" - ", text && *text ? _(text) :
"", NULL);
563 if ( !account_type_has_auto_interest_xfer( data->account_type ) )
567 data->xferData = gnc_xfer_dialog( GTK_WIDGET(data->startRecnWindow),
573 if ( account_type_has_auto_interest_payment( data->account_type ) )
574 title = gnc_recn_make_interest_window_name( data->account,
575 _(
"Interest Payment") );
577 title = gnc_recn_make_interest_window_name( data->account,
578 _(
"Interest Charge") );
580 gnc_xfer_dialog_set_title( data->xferData, title );
585 gnc_xfer_dialog_set_information_label( data->xferData,
586 _(
"Payment Information") );
593 if ( account_type_has_auto_interest_payment( data->account_type ) )
595 gnc_xfer_dialog_set_from_account_label( data->xferData,
597 gnc_xfer_dialog_set_from_show_button_active( data->xferData, TRUE );
601 gnc_xfer_dialog_set_to_account_label( data->xferData,
602 _(
"Reconcile Account") );
603 gnc_xfer_dialog_select_to_account( data->xferData, data->account );
604 gnc_xfer_dialog_lock_to_account_tree( data->xferData );
607 gnc_xfer_dialog_quickfill_to_account( data->xferData, TRUE );
611 gnc_xfer_dialog_set_from_account_label( data->xferData,
612 _(
"Reconcile Account") );
613 gnc_xfer_dialog_select_from_account( data->xferData, data->account );
614 gnc_xfer_dialog_lock_from_account_tree( data->xferData );
616 gnc_xfer_dialog_set_to_account_label( data->xferData,
618 gnc_xfer_dialog_set_to_show_button_active( data->xferData, TRUE );
623 gnc_xfer_dialog_quickfill_to_account( data->xferData, FALSE );
627 gnc_xfer_dialog_toggle_currency_table( data->xferData, FALSE );
630 gnc_xfer_dialog_set_date( data->xferData, data->date );
639 if ( ! gnc_xfer_dialog_run_until_done( data->xferData ) )
640 if ( data->xfer_button )
641 gtk_widget_set_sensitive(GTK_WIDGET(data->xfer_button), TRUE);
644 data->xferData = NULL;
654 GtkWidget *entry = gnc_amount_edit_gtk_entry(
655 GNC_AMOUNT_EDIT(data->end_value) );
656 gnc_numeric before = gnc_amount_edit_get_amount(
657 GNC_AMOUNT_EDIT(data->end_value) );
660 recnInterestXferWindow( data );
668 if (gnc_reverse_balance(data->account))
671 gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (data->end_value), after);
672 gtk_widget_grab_focus(GTK_WIDGET(entry));
673 gtk_editable_select_region (GTK_EDITABLE(entry), 0, -1);
674 data->original_value = after;
675 data->user_set_value = FALSE;
684 if ( data->xfer_button )
685 gtk_widget_set_sensitive(GTK_WIDGET(data->xfer_button), FALSE);
688 gnc_reconcile_interest_xfer_run( data );
693 gnc_save_reconcile_interval(
Account *account,
time64 statement_date)
695 time64 prev_statement_date;
696 int days = 0, months = 0;
704 auto seconds = statement_date - prev_statement_date;
705 days = seconds / 60 / 60 / 24;
713 int prev_days = 0, prev_months = 1;
717 if (prev_months == 1)
725 struct tm current, prev;
729 months = ((12 * current.tm_year + current.tm_mon) -
730 (12 * prev.tm_year + prev.tm_mon));
737 if (months >= 0 && days >= 0)
757 startRecnWindow(GtkWidget *parent,
Account *account,
758 gnc_numeric *new_ending,
time64 *statement_date,
759 gboolean enable_subaccount)
761 GtkWidget *dialog, *end_value, *date_value, *include_children_button;
764 gboolean auto_interest_xfer_option;
770 gulong fo_handler_id;
778 data.account = account;
780 data.date = *statement_date;
785 data.include_children = !has_account_different_commodities(account) &&
788 ending = gnc_ui_account_get_reconciled_balance(account,
789 data.include_children);
790 print_info = gnc_account_print_info (account, TRUE);
800 builder = gtk_builder_new();
801 gnc_builder_add_from_file (builder,
"window-reconcile.glade",
"reconcile_start_dialog");
803 dialog = GTK_WIDGET(gtk_builder_get_object (builder,
"reconcile_start_dialog"));
806 gtk_widget_set_name (GTK_WIDGET(dialog),
"gnc-id-reconcile-start");
808 title = gnc_recn_make_window_name (account);
809 gtk_window_set_title(GTK_WINDOW(dialog), title);
812 data.startRecnWindow = GTK_WIDGET(dialog);
815 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
818 GtkWidget *start_value, *box;
820 GtkWidget *interest = NULL;
822 start_value = GTK_WIDGET(gtk_builder_get_object (builder,
"start_value"));
823 gtk_label_set_text(GTK_LABEL(start_value),
xaccPrintAmount (ending, print_info));
825 include_children_button = GTK_WIDGET(gtk_builder_get_object (builder,
"subaccount_check"));
826 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(include_children_button),
827 data.include_children);
828 gtk_widget_set_sensitive(include_children_button, enable_subaccount);
830 date_value = gnc_date_edit_new(*statement_date, FALSE, FALSE);
831 data.date_value = date_value;
832 box = GTK_WIDGET(gtk_builder_get_object (builder,
"date_value_box"));
833 gtk_box_pack_start(GTK_BOX(box), date_value, TRUE, TRUE, 0);
834 label = GTK_WIDGET(gtk_builder_get_object (builder,
"date_label"));
835 gnc_date_make_mnemonic_target(GNC_DATE_EDIT(date_value), label);
837 end_value = gnc_amount_edit_new ();
838 data.end_value = GNC_AMOUNT_EDIT(end_value);
839 data.original_value = *new_ending;
840 data.user_set_value = FALSE;
842 data.future_icon = GTK_WIDGET(gtk_builder_get_object (builder,
"future_icon"));
843 data.future_text = GTK_WIDGET(gtk_builder_get_object (builder,
"future_text"));
845 box = GTK_WIDGET(gtk_builder_get_object (builder,
"ending_value_box"));
846 gtk_box_pack_start(GTK_BOX(box), end_value, TRUE, TRUE, 0);
847 label = GTK_WIDGET(gtk_builder_get_object (builder,
"end_label"));
848 gnc_amount_edit_make_mnemonic_target (GNC_AMOUNT_EDIT(end_value), label);
850 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, &data);
852 gnc_date_activates_default(GNC_DATE_EDIT(date_value), TRUE);
855 g_signal_connect ( G_OBJECT (date_value),
"date_changed",
856 G_CALLBACK (recn_date_changed_cb), (gpointer) &data );
858 print_info.use_symbol = 0;
859 gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (end_value), print_info);
860 gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (end_value),
863 gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (end_value), *new_ending);
865 entry = gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT (end_value));
866 gtk_editable_select_region (GTK_EDITABLE(entry), 0, -1);
867 fo_handler_id = g_signal_connect (G_OBJECT(entry),
"focus-out-event",
868 G_CALLBACK(amount_edit_focus_out_cb),
870 g_signal_connect (G_OBJECT(entry),
"activate",
871 G_CALLBACK(amount_edit_cb),
873 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
879 interest = GTK_WIDGET(gtk_builder_get_object (builder,
"interest_button"));
880 if ( account_type_has_auto_interest_payment( data.account_type ) )
881 gtk_button_set_label(GTK_BUTTON(interest), _(
"Enter _Interest Payment…") );
882 else if ( account_type_has_auto_interest_charge( data.account_type ) )
883 gtk_button_set_label(GTK_BUTTON(interest), _(
"Enter _Interest Charge…") );
886 gtk_widget_destroy(interest);
892 data.xfer_button = interest;
893 if ( auto_interest_xfer_option )
894 gtk_widget_set_sensitive(GTK_WIDGET(interest), FALSE);
897 gtk_widget_show_all(dialog);
899 gtk_widget_hide (data.future_text);
900 gtk_widget_hide (data.future_icon);
902 gtk_widget_grab_focus(gnc_amount_edit_gtk_entry
903 (GNC_AMOUNT_EDIT (end_value)));
908 if ( account_type_has_auto_interest_xfer( data.account_type )
909 && auto_interest_xfer_option )
911 gnc_reconcile_interest_xfer_run( &data );
914 while (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
916 if (gnc_date_edit_get_date_end(GNC_DATE_EDIT(date_value)) != *statement_date)
917 recn_date_changed_cb(date_value, &data);
920 if (gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(end_value), NULL))
922 result = GTK_RESPONSE_OK;
927 if (result == GTK_RESPONSE_OK)
929 *new_ending = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (end_value));
930 *statement_date = gnc_date_edit_get_date_end(GNC_DATE_EDIT(date_value));
932 if (gnc_reverse_balance(account))
937 gnc_save_reconcile_interval(account, *statement_date);
940 g_signal_handler_disconnect (G_OBJECT(entry), fo_handler_id);
941 gtk_widget_destroy (dialog);
942 g_object_unref(G_OBJECT(builder));
944 return (result == GTK_RESPONSE_OK);
949 gnc_reconcile_window_set_sensitivity(RecnWindow *recnData)
951 gboolean sensitive = FALSE;
955 view = GNC_RECONCILE_VIEW(recnData->debit);
956 if (gnc_reconcile_view_num_selected(view) == 1)
959 view = GNC_RECONCILE_VIEW(recnData->credit);
960 if (gnc_reconcile_view_num_selected(view) == 1)
963 action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
965 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), sensitive);
967 action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
968 "TransDeleteAction");
969 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), sensitive);
973 view = GNC_RECONCILE_VIEW(recnData->debit);
974 if (gnc_reconcile_view_num_selected(view) > 0)
977 view = GNC_RECONCILE_VIEW(recnData->credit);
978 if (gnc_reconcile_view_num_selected(view) > 0)
981 action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
983 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), sensitive);
985 action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group),
987 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), sensitive);
995 auto recnData =
static_cast<RecnWindow*
>(data);
996 gnc_reconcile_window_set_sensitivity(recnData);
997 recnRecalculateBalance(recnData);
1005 auto recnData =
static_cast<RecnWindow*
>(data);
1006 gnc_reconcile_window_set_sensitivity(recnData);
1023 do_popup_menu(RecnWindow *recnData, GdkEventButton *event)
1025 GMenuModel *menu_model = (GMenuModel *)gtk_builder_get_object (recnData->builder,
1027 GtkWidget *menu = gtk_menu_new_from_model (menu_model);
1032 gtk_menu_attach_to_widget (GTK_MENU(menu), GTK_WIDGET(recnData->window), NULL);
1033 gtk_menu_popup_at_pointer (GTK_MENU(menu), (GdkEvent *) event);
1051 gnc_reconcile_window_popup_menu_cb (GtkWidget *widget,
1052 RecnWindow *recnData)
1054 do_popup_menu(recnData, NULL);
1064 gnc_reconcile_window_button_press_cb (GtkWidget *widget,
1065 GdkEventButton *event,
1066 RecnWindow *recnData)
1068 if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1070 GNCQueryView *qview = GNC_QUERY_VIEW(widget);
1074 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(qview),
1077 &path, NULL, NULL, NULL);
1081 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(qview));
1083 if (!gtk_tree_selection_path_is_selected (selection, path))
1085 gtk_tree_selection_unselect_all (selection);
1086 gtk_tree_selection_select_path (selection, path);
1088 gtk_tree_path_free (path);
1090 do_popup_menu (recnData, event);
1097 static GNCSplitReg *
1098 gnc_reconcile_window_open_register(RecnWindow *recnData)
1100 Account *account = recn_get_account (recnData);
1102 gboolean include_children;
1111 gnc_split_reg_raise (gsr);
1120 auto recnData =
static_cast<RecnWindow*
>(data);
1127 gsr = gnc_reconcile_window_open_register(recnData);
1132 if (gnc_split_reg_clear_filter_for_split (gsr, split))
1135 gnc_split_reg_jump_to_split( gsr, split );
1140 gnc_reconcile_window_focus_cb(GtkWidget *widget, GdkEventFocus *event,
1143 auto recnData =
static_cast<RecnWindow*
>(data);
1147 this_view = GNC_RECONCILE_VIEW(widget);
1149 debit = GNC_RECONCILE_VIEW(recnData->debit);
1150 credit = GNC_RECONCILE_VIEW(recnData->credit);
1152 other_view = GNC_RECONCILE_VIEW(this_view == debit ? credit : debit);
1155 gnc_reconcile_view_unselect_all(other_view);
1160 gnc_reconcile_key_press_cb (GtkWidget *widget, GdkEventKey *event,
1163 auto recnData =
static_cast<RecnWindow*
>(data);
1164 GtkWidget *this_view, *other_view;
1165 GtkWidget *debit, *credit;
1167 switch (event->keyval)
1170 case GDK_KEY_ISO_Left_Tab:
1177 g_signal_stop_emission_by_name (widget,
"key_press_event");
1181 debit = recnData->debit;
1182 credit = recnData->credit;
1184 other_view = (this_view == debit ? credit : debit);
1186 gtk_widget_grab_focus (other_view);
1193 gnc_reconcile_window_set_titles(RecnWindow *recnData)
1198 gtk_frame_set_label(GTK_FRAME(recnData->debit_frame), title);
1201 gtk_frame_set_label(GTK_FRAME(recnData->credit_frame), title);
1206 gnc_reconcile_window_create_view_box(
Account *account,
1207 GNCReconcileViewType type,
1208 RecnWindow *recnData,
1209 GtkWidget **list_save,
1210 GtkWidget **total_save)
1212 GtkWidget *frame, *scrollWin, *view, *vbox, *label, *hbox;
1214 GtkRequisition nat_sb;
1216 frame = gtk_frame_new(NULL);
1218 if (type == RECLIST_DEBIT)
1219 recnData->debit_frame = frame;
1221 recnData->credit_frame = frame;
1223 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
1224 gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE);
1226 view = gnc_reconcile_view_new(account, type, recnData->statement_date);
1229 g_signal_connect(view,
"toggle_reconciled",
1230 G_CALLBACK(gnc_reconcile_window_toggled_cb),
1232 g_signal_connect(view,
"line_selected",
1233 G_CALLBACK(gnc_reconcile_window_row_cb),
1235 g_signal_connect(view,
"button_press_event",
1236 G_CALLBACK(gnc_reconcile_window_button_press_cb),
1238 g_signal_connect(view,
"double_click_split",
1239 G_CALLBACK(gnc_reconcile_window_double_click_cb),
1241 g_signal_connect(view,
"focus_in_event",
1242 G_CALLBACK(gnc_reconcile_window_focus_cb),
1244 g_signal_connect(view,
"key_press_event",
1245 G_CALLBACK(gnc_reconcile_key_press_cb),
1248 scrollWin = gtk_scrolled_window_new (NULL, NULL);
1249 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrollWin),
1250 GTK_POLICY_AUTOMATIC,
1251 GTK_POLICY_AUTOMATIC);
1252 gtk_container_set_border_width(GTK_CONTAINER(scrollWin), 5);
1254 gtk_container_add(GTK_CONTAINER(frame), scrollWin);
1255 gtk_container_add(GTK_CONTAINER(scrollWin), view);
1256 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
1259 vscroll = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (scrollWin));
1260 gtk_widget_get_preferred_size (vscroll, NULL, &nat_sb);
1263 gnc_reconcile_view_add_padding (GNC_RECONCILE_VIEW(view), REC_RECN, nat_sb.width);
1265 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
1266 gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
1267 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1269 label = gtk_label_new(_(
"Total"));
1270 gnc_label_set_alignment(label, 1.0, 0.5);
1271 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
1273 label = gtk_label_new(
"");
1274 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1275 *total_save = label;
1276 gtk_widget_set_margin_end (GTK_WIDGET(label), 10 + nat_sb.width);
1283 gnc_reconcile_window_get_current_split(RecnWindow *recnData)
1288 view = GNC_RECONCILE_VIEW(recnData->debit);
1289 split = gnc_reconcile_view_get_current_split(view);
1293 view = GNC_RECONCILE_VIEW(recnData->credit);
1294 split = gnc_reconcile_view_get_current_split(view);
1301 gnc_ui_reconcile_window_help_cb (GSimpleAction *simple,
1302 GVariant *parameter,
1305 auto recnData =
static_cast<RecnWindow*
>(user_data);
1306 gnc_gnome_help (GTK_WINDOW(recnData->window), DF_MANUAL, DL_RECNWIN);
1311 gnc_ui_reconcile_window_change_cb (GSimpleAction *simple,
1312 GVariant *parameter,
1315 auto recnData =
static_cast<RecnWindow*
>(user_data);
1316 Account *account = recn_get_account (recnData);
1317 gnc_numeric new_ending = recnData->new_ending;
1318 time64 statement_date = recnData->statement_date;
1320 if (gnc_reverse_balance (account))
1322 if (startRecnWindow (recnData->window, account, &new_ending, &statement_date,
1325 recnData->new_ending = new_ending;
1326 recnData->statement_date = statement_date;
1327 recnRecalculateBalance (recnData);
1333 gnc_ui_reconcile_window_balance_cb (GSimpleAction *simple,
1334 GVariant *parameter,
1337 auto recnData =
static_cast<RecnWindow*
>(user_data);
1340 gnc_numeric balancing_amount;
1344 gsr = gnc_reconcile_window_open_register(recnData);
1348 account = recn_get_account(recnData);
1349 if (account == NULL)
1352 balancing_amount = recnRecalculateBalance(recnData);
1356 statement_date = recnData->statement_date;
1357 if (statement_date == 0)
1360 gnc_split_reg_balancing_entry(gsr, account, statement_date, balancing_amount);
1365 gnc_ui_reconcile_window_rec_cb (GSimpleAction *simple,
1366 GVariant *parameter,
1369 auto recnData =
static_cast<RecnWindow*
>(user_data);
1372 debit = GNC_RECONCILE_VIEW(recnData->debit);
1373 credit = GNC_RECONCILE_VIEW(recnData->credit);
1375 gnc_reconcile_view_set_list (debit, TRUE);
1376 gnc_reconcile_view_set_list (credit, TRUE);
1381 gnc_ui_reconcile_window_unrec_cb (GSimpleAction *simple,
1382 GVariant *parameter,
1385 auto recnData =
static_cast<RecnWindow*
>(user_data);
1388 debit = GNC_RECONCILE_VIEW(recnData->debit);
1389 credit = GNC_RECONCILE_VIEW(recnData->credit);
1391 gnc_reconcile_view_set_list (debit, FALSE);
1392 gnc_reconcile_view_set_list (credit, FALSE);
1402 gnc_reconcile_window_get_selection_view (RecnWindow *recnData)
1404 if (gnc_reconcile_view_num_selected (GNC_RECONCILE_VIEW (recnData->debit)) > 0)
1405 return GNC_RECONCILE_VIEW (recnData->debit);
1407 if (gnc_reconcile_view_num_selected (GNC_RECONCILE_VIEW (recnData->credit)) > 0)
1408 return GNC_RECONCILE_VIEW (recnData->credit);
1421 gnc_reconcile_window_delete_set_next_selection (RecnWindow *recnData, Split *split)
1423 GNCReconcileView *view = gnc_reconcile_window_get_selection_view (recnData);
1424 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1425 Split *this_split = NULL;
1427 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1428 GList *path_list, *node;
1429 GtkTreePath *save_del_path;
1435 path_list = gtk_tree_selection_get_selected_rows (selection, &model);
1437 node = g_list_first (path_list);
1440 auto path =
static_cast<GtkTreePath*
>(node->data);
1441 save_del_path = gtk_tree_path_copy (path);
1443 gtk_tree_path_next (path);
1444 if (gtk_tree_model_get_iter (model, &iter, path))
1448 gtk_tree_model_get (model, &iter, REC_POINTER, &this_split, -1);
1450 while (
xaccSplitGetParent (this_split) == trans && gtk_tree_model_iter_next (model, &iter));
1457 path = save_del_path;
1458 if (gtk_tree_path_prev (path) && gtk_tree_model_get_iter (model, &iter, path))
1462 gtk_tree_model_get (model, &iter, REC_POINTER, &this_split, -1);
1464 while (
xaccSplitGetParent (this_split) == trans && gtk_tree_model_iter_previous (model, &iter));
1468 gtk_tree_path_free (save_del_path);
1469 g_list_free_full (path_list, (GDestroyNotify) gtk_tree_path_free);
1473 gtk_tree_selection_select_iter (selection, &iter);
1478 gnc_ui_reconcile_window_delete_cb (GSimpleAction *simple,
1479 GVariant *parameter,
1482 auto recnData =
static_cast<RecnWindow*
>(user_data);
1486 split = gnc_reconcile_window_get_current_split(recnData);
1492 const char *message = _(
"Are you sure you want to delete the selected " 1496 result = gnc_verify_dialog (GTK_WINDOW (recnData->window), FALSE,
"%s", message);
1503 gnc_reconcile_window_delete_set_next_selection(recnData, split);
1505 gnc_suspend_gui_refresh ();
1510 gnc_resume_gui_refresh ();
1515 gnc_ui_reconcile_window_edit_cb (GSimpleAction *simple,
1516 GVariant *parameter,
1519 auto recnData =
static_cast<RecnWindow*
>(user_data);
1523 split = gnc_reconcile_window_get_current_split (recnData);
1528 gsr = gnc_reconcile_window_open_register(recnData);
1533 if (gnc_split_reg_clear_filter_for_split (gsr, split))
1536 gnc_split_reg_jump_to_split_amount( gsr, split );
1541 gnc_recn_make_window_name(
Account *account)
1547 title = g_strconcat(fullname,
" - ", _(
"Reconcile"), NULL);
1556 gnc_recn_set_window_name(RecnWindow *recnData)
1560 title = gnc_recn_make_window_name (recn_get_account (recnData));
1562 gtk_window_set_title (GTK_WINDOW (recnData->window), title);
1569 gnc_recn_edit_account_cb (GSimpleAction *simple,
1570 GVariant *parameter,
1573 auto recnData =
static_cast<RecnWindow*
>(user_data);
1574 Account *account = recn_get_account (recnData);
1576 if (account == NULL)
1584 gnc_recn_xfer_cb (GSimpleAction *simple,
1585 GVariant *parameter,
1588 auto recnData =
static_cast<RecnWindow*
>(user_data);
1589 Account *account = recn_get_account (recnData);
1591 if (account == NULL)
1594 gnc_xfer_dialog (recnData->window, account);
1599 gnc_recn_scrub_cb (GSimpleAction *simple,
1600 GVariant *parameter,
1603 auto recnData =
static_cast<RecnWindow*
>(user_data);
1604 Account *account = recn_get_account (recnData);
1606 if (account == NULL)
1609 gnc_suspend_gui_refresh ();
1612 xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
1615 if (g_getenv(
"GNC_AUTO_SCRUB_LOTS") != NULL)
1616 xaccAccountTreeScrubLots(account);
1618 gnc_resume_gui_refresh ();
1623 gnc_recn_open_cb (GSimpleAction *simple,
1624 GVariant *parameter,
1627 auto recnData =
static_cast<RecnWindow*
>(user_data);
1629 gnc_reconcile_window_open_register(recnData);
1634 gnc_get_reconcile_info (
Account *account,
1635 gnc_numeric *new_ending,
1638 gboolean always_today;
1642 g_date_clear(&date, 1);
1644 always_today =
gnc_prefs_get_bool(GNC_PREFS_GROUP_RECONCILE, GNC_PREF_ALWAYS_REC_TO_TODAY);
1646 if (!always_today &&
1649 int months = 1, days = 0;
1657 gboolean was_last_day_of_month = g_date_is_last_of_month(&date);
1659 g_date_add_months(&date, months);
1662 if (was_last_day_of_month)
1664 g_date_set_day (&date, g_date_get_days_in_month(g_date_get_month(&date),
1665 g_date_get_year( &date)));
1670 g_date_add_days (&date, days);
1676 if (*statement_date > today)
1677 *statement_date = today;
1684 if (gnc_reverse_balance(account))
1693 gnc_ui_account_get_balance_as_of_date
1694 (account, *statement_date,
1701 find_by_account (gpointer
find_data, gpointer user_data)
1704 auto recnData =
static_cast<RecnWindow*
>(user_data);
1714 recn_set_watches_one_account (gpointer data, gpointer user_data)
1717 RecnWindow *recnData = (RecnWindow *)user_data;
1720 gnc_gui_component_watch_entity (recnData->component_id,
1722 QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
1725 for (
auto split : xaccAccountGetSplits (account))
1728 gnc_gui_component_watch_entity (recnData->component_id,
1732 | GNC_EVENT_ITEM_CHANGED);
1738 recn_set_watches (RecnWindow *recnData)
1740 gboolean include_children;
1742 GList *accounts = NULL;
1744 gnc_gui_component_clear_watches (recnData->component_id);
1746 account = recn_get_account (recnData);
1749 if (include_children)
1753 accounts = g_list_prepend (accounts, account);
1755 g_list_foreach(accounts, recn_set_watches_one_account, recnData);
1757 g_list_free (accounts);
1762 refresh_handler (GHashTable *changes, gpointer user_data)
1764 auto recnData =
static_cast<RecnWindow*
>(user_data);
1768 account = recn_get_account (recnData);
1771 gnc_close_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
1777 info = gnc_gui_get_entity_events (changes, &recnData->account);
1778 if (info && (info->event_mask & QOF_EVENT_DESTROY))
1780 gnc_close_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
1785 gnc_reconcile_window_set_titles(recnData);
1786 recn_set_watches (recnData);
1788 recnRefresh (recnData);
1793 close_handler (gpointer user_data)
1795 auto recnData =
static_cast<RecnWindow*
>(user_data);
1797 gnc_save_window_size(GNC_PREFS_GROUP_RECONCILE, GTK_WINDOW(recnData->window));
1798 gtk_widget_destroy (recnData->window);
1811 recnWindow (GtkWidget *parent,
Account *account)
1813 gnc_numeric new_ending;
1814 gboolean enable_subaccounts;
1817 if (account == NULL)
1827 if (!gnc_reconcile_last_statement_date)
1830 statement_date = gnc_reconcile_last_statement_date;
1832 gnc_get_reconcile_info (account, &new_ending, &statement_date);
1834 enable_subaccounts = !has_account_different_commodities(account);
1837 if (!startRecnWindow (parent, account, &new_ending, &statement_date,
1838 enable_subaccounts))
1841 return recnWindowWithBalance (parent, account, new_ending, statement_date);
1845 static GActionEntry recWindow_actions_entries [] =
1847 {
"RecnChangeInfoAction", gnc_ui_reconcile_window_change_cb, NULL, NULL, NULL },
1848 {
"RecnFinishAction", recnFinishCB, NULL, NULL, NULL },
1849 {
"RecnPostponeAction", recnPostponeCB, NULL, NULL, NULL },
1850 {
"RecnCancelAction", recnCancelCB, NULL, NULL, NULL },
1851 {
"RecnAutoClearAction", recnAutoClearCB, NULL, NULL, NULL },
1853 {
"AccountOpenAccountAction", gnc_recn_open_cb, NULL, NULL, NULL },
1854 {
"AccountEditAccountAction", gnc_recn_edit_account_cb, NULL, NULL, NULL },
1855 {
"AccountTransferAction", gnc_recn_xfer_cb, NULL, NULL, NULL },
1856 {
"AccountCheckRepairAction", gnc_recn_scrub_cb, NULL, NULL, NULL },
1858 {
"TransBalanceAction", gnc_ui_reconcile_window_balance_cb, NULL, NULL, NULL },
1859 {
"TransEditAction", gnc_ui_reconcile_window_edit_cb, NULL, NULL, NULL },
1860 {
"TransDeleteAction", gnc_ui_reconcile_window_delete_cb, NULL, NULL, NULL },
1861 {
"TransRecAction", gnc_ui_reconcile_window_rec_cb, NULL, NULL, NULL },
1862 {
"TransUnRecAction", gnc_ui_reconcile_window_unrec_cb, NULL, NULL, NULL },
1864 {
"HelpHelpAction", gnc_ui_reconcile_window_help_cb, NULL, NULL, NULL },
1867 static guint recnWindow_n_actions_entries = G_N_ELEMENTS(recWindow_actions_entries);
1869 #ifdef MAC_INTEGRATION 1872 can_activate_cb(GtkWidget *widget, guint signal_id, gpointer data)
1892 recnWindowWithBalance (GtkWidget *parent,
Account *account, gnc_numeric new_ending,
1895 RecnWindow *recnData;
1896 GtkWidget *statusbar;
1900 if (account == NULL)
1903 recnData =
static_cast<RecnWindow*
>(gnc_find_first_gui_component (WINDOW_RECONCILE_CM_CLASS,
1904 find_by_account, account));
1908 recnData = g_new0 (RecnWindow, 1);
1913 recnData->component_id =
1914 gnc_register_gui_component (WINDOW_RECONCILE_CM_CLASS,
1915 refresh_handler, close_handler,
1917 gnc_gui_component_set_session (recnData->component_id, gnc_get_current_session());
1919 recn_set_watches (recnData);
1921 gnc_reconcile_last_statement_date = statement_date;
1923 recnData->new_ending = new_ending;
1924 recnData->statement_date = statement_date;
1925 recnData->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1926 recnData->delete_refresh = FALSE;
1927 new (&recnData->autoclear_splits) SplitsVec();
1928 new (&recnData->initially_cleared_splits) SplitsVec();
1930 gnc_recn_set_window_name(recnData);
1932 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1933 gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE);
1934 gtk_container_add(GTK_CONTAINER(recnData->window), vbox);
1937 gtk_widget_set_name (GTK_WIDGET(recnData->window),
"gnc-id-reconcile");
1939 dock = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1940 gtk_box_set_homogeneous (GTK_BOX (dock), FALSE);
1941 gtk_widget_show(dock);
1942 gtk_box_pack_start(GTK_BOX (vbox), dock, FALSE, TRUE, 0);
1944 auto init_cleared = [&recnData](Split* s)
1947 recnData->initially_cleared_splits.push_back (s);
1949 gnc_account_foreach_split_until_date (account, statement_date, init_cleared);
1952 GtkToolbar *tool_bar;
1953 GMenuModel *menu_model;
1954 GtkWidget *menu_bar;
1955 const gchar *ui = GNUCASH_RESOURCE_PREFIX
"/gnc-reconcile-window.ui";
1956 GError *error = NULL;
1958 recnData->accel_group = gtk_accel_group_new ();
1959 recnData->builder = gtk_builder_new ();
1961 gtk_builder_add_from_resource (recnData->builder, ui, &error);
1963 gtk_builder_set_translation_domain (recnData->builder, PROJECT_NAME);
1967 g_critical (
"Failed to load ui resource %s, Error %s", ui, error->message);
1968 g_error_free (error);
1969 gnc_unregister_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
1974 recnData->autoclear_button = GTK_WIDGET(gtk_builder_get_object(recnData->builder,
"autoclear_button"));
1976 menu_model = (GMenuModel *)gtk_builder_get_object (recnData->builder,
"recwin-menu");
1977 menu_bar = gtk_menu_bar_new_from_model (menu_model);
1978 gtk_container_add (GTK_CONTAINER(vbox), menu_bar);
1979 #ifdef MAC_INTEGRATION 1980 auto theApp =
static_cast<GtkosxApplication*
>(g_object_new (GTKOSX_TYPE_APPLICATION, NULL));
1981 gtk_widget_hide (menu_bar);
1982 gtk_widget_set_no_show_all (menu_bar, TRUE);
1983 if (GTK_IS_MENU_ITEM (menu_bar))
1984 menu_bar = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_bar));
1986 gtkosx_application_set_menu_bar (theApp, GTK_MENU_SHELL (menu_bar));
1988 tool_bar = (GtkToolbar *)gtk_builder_get_object (recnData->builder,
"recwin-toolbar");
1990 gtk_toolbar_set_style (GTK_TOOLBAR(tool_bar), GTK_TOOLBAR_BOTH);
1991 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tool_bar),
1992 GTK_ICON_SIZE_SMALL_TOOLBAR);
1994 gtk_container_add (GTK_CONTAINER(vbox), GTK_WIDGET(tool_bar));
1996 gtk_window_add_accel_group (GTK_WINDOW(recnData->window), recnData->accel_group);
2001 #ifdef MAC_INTEGRATION 2002 gtkosx_application_sync_menubar (theApp);
2003 g_signal_connect (menu_bar,
"can-activate-accel",
2004 G_CALLBACK(can_activate_cb), NULL);
2005 g_object_unref (theApp);
2009 recnData->simple_action_group = g_simple_action_group_new ();
2011 g_action_map_add_action_entries (G_ACTION_MAP(recnData->simple_action_group),
2012 recWindow_actions_entries,
2013 recnWindow_n_actions_entries,
2016 gtk_widget_insert_action_group (GTK_WIDGET(recnData->window),
"recwin",
2017 G_ACTION_GROUP(recnData->simple_action_group));
2020 g_signal_connect(recnData->window,
"popup-menu",
2021 G_CALLBACK(gnc_reconcile_window_popup_menu_cb), recnData);
2023 statusbar = gtk_statusbar_new();
2024 gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
2026 g_signal_connect (recnData->window,
"destroy",
2027 G_CALLBACK(recn_destroy_cb), recnData);
2028 g_signal_connect (recnData->window,
"delete_event",
2029 G_CALLBACK(recn_delete_cb), recnData);
2030 g_signal_connect (recnData->window,
"key_press_event",
2031 G_CALLBACK(recn_key_press_cb), recnData);
2037 GtkStatusbar *bar = GTK_STATUSBAR (statusbar);
2038 guint context = gtk_statusbar_get_context_id (bar,
"future_dates");
2039 GtkWidget *box = gtk_statusbar_get_message_area (bar);
2040 GtkWidget *image = gtk_image_new_from_icon_name
2041 (
"dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR);
2045 auto has_later_recn_statement_date = [statement_date](
const Split *split)
2053 PWARN (
"split posting_date=%s, recn_date=%s", datestr, recnstr);
2055 gtk_statusbar_push (bar, context, _(
"WARNING! Account contains \ 2056 splits whose reconcile date is after statement date. Reconciliation may be \ 2059 gtk_widget_set_tooltip_text (GTK_WIDGET (bar), _(
"This account \ 2060 has splits whose Reconciled Date is after this reconciliation statement date. \ 2061 These splits may make reconciliation difficult. If this is the case, you may \ 2062 use Find Transactions to find them, unreconcile, and re-reconcile."));
2064 gtk_box_pack_start (GTK_BOX(box), image, FALSE, FALSE, 0);
2065 gtk_box_reorder_child (GTK_BOX(box), image, 0);
2074 GtkWidget *frame = gtk_frame_new(NULL);
2075 GtkWidget *main_area = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
2076 GtkWidget *debcred_area = gtk_grid_new ();
2077 GtkWidget *debits_box;
2078 GtkWidget *credits_box;
2080 gtk_box_set_homogeneous (GTK_BOX (main_area), FALSE);
2081 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 10);
2084 gtk_window_set_default_size(GTK_WINDOW(recnData->window), 800, 600);
2085 gnc_restore_window_size (GNC_PREFS_GROUP_RECONCILE,
2086 GTK_WINDOW(recnData->window), GTK_WINDOW(parent));
2088 gtk_container_add(GTK_CONTAINER(frame), main_area);
2089 gtk_container_set_border_width(GTK_CONTAINER(main_area), 10);
2091 debits_box = gnc_reconcile_window_create_view_box
2092 (account, RECLIST_DEBIT, recnData,
2093 &recnData->debit, &recnData->total_debit);
2096 gnc_widget_style_context_add_class (GTK_WIDGET(debits_box),
"gnc-class-debits");
2098 credits_box = gnc_reconcile_window_create_view_box
2099 (account, RECLIST_CREDIT, recnData,
2100 &recnData->credit, &recnData->total_credit);
2103 gnc_widget_style_context_add_class (GTK_WIDGET(credits_box),
"gnc-class-credits");
2105 GNC_RECONCILE_VIEW(recnData->debit)->sibling = GNC_RECONCILE_VIEW(recnData->credit);
2106 GNC_RECONCILE_VIEW(recnData->credit)->sibling = GNC_RECONCILE_VIEW(recnData->debit);
2108 gtk_box_pack_start(GTK_BOX(main_area), debcred_area, TRUE, TRUE, 0);
2110 gtk_grid_set_column_homogeneous (GTK_GRID(debcred_area), TRUE);
2111 gtk_grid_set_column_spacing (GTK_GRID(debcred_area), 15);
2112 gtk_grid_attach (GTK_GRID(debcred_area), debits_box, 0, 0, 1, 1);
2113 gtk_widget_set_hexpand (debits_box, TRUE);
2114 gtk_widget_set_vexpand (debits_box, TRUE);
2115 gtk_widget_set_halign (debits_box, GTK_ALIGN_FILL);
2116 gtk_widget_set_valign (debits_box, GTK_ALIGN_FILL);
2118 gtk_grid_attach (GTK_GRID(debcred_area), credits_box, 1, 0, 1, 1);
2119 gtk_widget_set_hexpand (credits_box, TRUE);
2120 gtk_widget_set_vexpand (credits_box, TRUE);
2121 gtk_widget_set_halign (credits_box, GTK_ALIGN_FILL);
2122 gtk_widget_set_valign (credits_box, GTK_ALIGN_FILL);
2125 GtkWidget *hbox, *title_vbox, *value_vbox;
2126 GtkWidget *totals_hbox, *frame, *title, *value;
2129 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2130 gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
2131 gtk_box_pack_start(GTK_BOX(main_area), hbox, FALSE, FALSE, 0);
2134 frame = gtk_frame_new(NULL);
2135 gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, FALSE, 0);
2138 gtk_widget_set_name (GTK_WIDGET(frame),
"gnc-id-reconcile-totals");
2141 totals_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
2142 gtk_box_set_homogeneous (GTK_BOX (totals_hbox), FALSE);
2143 gtk_container_add(GTK_CONTAINER(frame), totals_hbox);
2144 gtk_container_set_border_width(GTK_CONTAINER(totals_hbox), 5);
2147 title_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
2148 gtk_box_set_homogeneous (GTK_BOX (title_vbox), FALSE);
2149 gtk_box_pack_start(GTK_BOX(totals_hbox), title_vbox, FALSE, FALSE, 0);
2152 value_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
2153 gtk_box_set_homogeneous (GTK_BOX (value_vbox), FALSE);
2154 gtk_box_pack_start(GTK_BOX(totals_hbox), value_vbox, TRUE, TRUE, 0);
2157 title = gtk_label_new(_(
"Statement Date"));
2158 gnc_label_set_alignment(title, 1.0, 0.5);
2159 gtk_box_pack_start(GTK_BOX(title_vbox), title, FALSE, FALSE, 0);
2161 value = gtk_label_new(
"");
2162 recnData->recn_date = value;
2163 gnc_label_set_alignment(value, 1.0, 0.5);
2164 gtk_box_pack_start(GTK_BOX(value_vbox), value, FALSE, FALSE, 0);
2167 title = gtk_label_new(_(
"Starting Balance"));
2168 gnc_label_set_alignment(title, 1.0, 0.5);
2169 gtk_box_pack_start(GTK_BOX(title_vbox), title, FALSE, FALSE, 3);
2171 value = gtk_label_new(
"");
2172 recnData->starting = value;
2173 gnc_label_set_alignment(value, 1.0, 0.5);
2174 gtk_box_pack_start(GTK_BOX(value_vbox), value, FALSE, FALSE, 3);
2177 title = gtk_label_new(_(
"Ending Balance"));
2178 gnc_label_set_alignment(title, 1.0, 0.5);
2179 gtk_box_pack_start(GTK_BOX(title_vbox), title, FALSE, FALSE, 0);
2181 value = gtk_label_new(
"");
2182 recnData->ending = value;
2183 gnc_label_set_alignment(value, 1.0, 0.5);
2184 gtk_box_pack_start(GTK_BOX(value_vbox), value, FALSE, FALSE, 0);
2187 title = gtk_label_new(_(
"Reconciled Balance"));
2188 gnc_label_set_alignment(title, 1.0, 0.5);
2189 gtk_box_pack_start(GTK_BOX(title_vbox), title, FALSE, FALSE, 0);
2191 value = gtk_label_new(
"");
2192 recnData->reconciled = value;
2193 gnc_label_set_alignment(value, 1.0, 0.5);
2194 gtk_box_pack_start(GTK_BOX(value_vbox), value, FALSE, FALSE, 0);
2197 title = gtk_label_new(_(
"Difference"));
2198 gnc_label_set_alignment(title, 1.0, 0.5);
2199 gtk_box_pack_start(GTK_BOX(title_vbox), title, FALSE, FALSE, 0);
2201 value = gtk_label_new(
"");
2202 recnData->difference = value;
2203 gnc_label_set_alignment(value, 1.0, 0.5);
2204 gtk_box_pack_start(GTK_BOX(value_vbox), value, FALSE, FALSE, 0);
2208 recnRefresh (recnData);
2212 gtk_window_set_resizable(GTK_WINDOW(recnData->window), TRUE);
2213 gtk_widget_show_all(recnData->window);
2215 gnc_reconcile_window_set_titles(recnData);
2217 recnRecalculateBalance(recnData);
2219 gnc_window_adjust_for_screen(GTK_WINDOW(recnData->window));
2222 gnc_query_sort_order(GNC_QUERY_VIEW(recnData->debit), REC_DATE, GTK_SORT_ASCENDING);
2223 gnc_query_sort_order(GNC_QUERY_VIEW(recnData->credit), REC_DATE, GTK_SORT_ASCENDING);
2225 gtk_widget_grab_focus (recnData->debit);
2228 gint recn_widthc = gnc_reconcile_view_get_column_width (GNC_RECONCILE_VIEW(recnData->credit), REC_RECN);
2229 gint recn_widthd = gnc_reconcile_view_get_column_width (GNC_RECONCILE_VIEW(recnData->debit), REC_RECN);
2231 gtk_widget_set_margin_end (GTK_WIDGET(recnData->total_credit), 10 + recn_widthc);
2232 gtk_widget_set_margin_end (GTK_WIDGET(recnData->total_debit), 10 + recn_widthd);
2245 gnc_ui_reconcile_window_raise(RecnWindow * recnData)
2247 if (recnData == NULL)
2250 if (recnData->window == NULL)
2253 gtk_window_present(GTK_WINDOW(recnData->window));
2257 gnc_ui_reconcile_window_get_window (RecnWindow * recnData)
2259 if (recnData == NULL || recnData->window == NULL)
2261 return GTK_WINDOW(recnData->window);
2276 recn_destroy_cb (GtkWidget *w, gpointer data)
2278 auto recnData =
static_cast<RecnWindow*
>(data);
2279 gchar **actions = g_action_group_list_actions (G_ACTION_GROUP(recnData->simple_action_group));
2280 gint num_actions = g_strv_length (actions);
2282 gnc_unregister_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
2284 if (recnData->delete_refresh)
2285 gnc_resume_gui_refresh ();
2287 if (recnData->builder)
2288 g_object_unref(recnData->builder);
2290 if (recnData->accel_group)
2291 g_object_unref(recnData->accel_group);
2293 recnData->autoclear_splits.~SplitsVec();
2294 recnData->initially_cleared_splits.~SplitsVec();
2297 for (gint i = 0; i < num_actions; i++)
2299 GAction *action = g_action_map_lookup_action (G_ACTION_MAP(recnData->simple_action_group), actions[i]);
2300 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
2302 g_strfreev (actions);
2308 recn_cancel(RecnWindow *recnData)
2310 gboolean changed = FALSE;
2312 if (gnc_reconcile_view_changed(GNC_RECONCILE_VIEW(recnData->credit)))
2314 if (gnc_reconcile_view_changed(GNC_RECONCILE_VIEW(recnData->debit)))
2319 const char *message = _(
"You have made changes to this reconcile " 2320 "window. Are you sure you want to cancel?");
2321 if (!gnc_verify_dialog (GTK_WINDOW (recnData->window), FALSE,
"%s", message))
2325 gnc_close_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
2330 recn_delete_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
2332 auto recnData =
static_cast<RecnWindow*
>(data);
2334 recn_cancel(recnData);
2340 recn_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
2342 auto recnData =
static_cast<RecnWindow*
>(data);
2344 if (event->keyval == GDK_KEY_Escape)
2346 recn_cancel(recnData);
2366 find_payment_account(
Account *account)
2368 if (account ==
nullptr)
2371 const auto& splits = xaccAccountGetSplits (account);
2374 for (
auto it = splits.rbegin(); it != splits.rend(); it++)
2384 auto s = GNC_SPLIT(n->data);
2402 acct_traverse_descendants (
Account *acct, std::function<
void(
Account*)> fn)
2406 gnc_account_foreach_descendant (acct, fn);
2418 recnFinishCB (GSimpleAction *simple,
2419 GVariant *parameter,
2422 auto recnData =
static_cast<RecnWindow*
>(user_data);
2423 gboolean auto_payment;
2429 const char *message = _(
"The account is not balanced. " 2430 "Are you sure you want to finish?");
2431 if (!gnc_verify_dialog (GTK_WINDOW (recnData->window), FALSE,
"%s", message))
2435 date = recnData->statement_date;
2437 gnc_suspend_gui_refresh ();
2439 recnData->delete_refresh = TRUE;
2440 account = recn_get_account (recnData);
2443 gnc_reconcile_view_commit(GNC_RECONCILE_VIEW(recnData->credit), date);
2444 gnc_reconcile_view_commit(GNC_RECONCILE_VIEW(recnData->debit), date);
2447 auto_payment =
gnc_prefs_get_bool(GNC_PREFS_GROUP_RECONCILE, GNC_PREF_AUTO_CC_PAYMENT);
2461 gnc_xfer_dialog_set_amount(xfer,
gnc_numeric_neg (recnData->new_ending));
2463 payment_account = find_payment_account (account);
2464 if (payment_account != NULL)
2465 gnc_xfer_dialog_select_from_account (xfer, payment_account);
2468 gnc_close_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
2481 recnPostponeCB (GSimpleAction *simple,
2482 GVariant *parameter,
2485 auto recnData =
static_cast<RecnWindow*
>(user_data);
2489 const char *message = _(
"Do you want to postpone this reconciliation " 2490 "and finish it later?");
2491 if (!gnc_verify_dialog (GTK_WINDOW (recnData->window), FALSE,
"%s", message))
2495 gnc_suspend_gui_refresh ();
2497 recnData->delete_refresh = TRUE;
2498 account = recn_get_account (recnData);
2501 gnc_reconcile_view_postpone (GNC_RECONCILE_VIEW(recnData->credit));
2502 gnc_reconcile_view_postpone (GNC_RECONCILE_VIEW(recnData->debit));
2508 gnc_close_gui_component_by_data (WINDOW_RECONCILE_CM_CLASS, recnData);
2513 recnCancelCB (GSimpleAction *simple,
2514 GVariant *parameter,
2517 auto recnData =
static_cast<RecnWindow*
>(user_data);
2518 recn_cancel(recnData);
2531 recnAutoClearCB (GSimpleAction *simple,
2532 GVariant *parameter,
2535 auto recnData =
static_cast<RecnWindow*
>(user_data);
2537 if (recnData->autoclear_splits.empty())
2540 gnc_suspend_gui_refresh ();
2541 gnc_reconcile_view_unclear_all (GNC_RECONCILE_VIEW(recnData->debit));
2542 gnc_reconcile_view_unclear_all (GNC_RECONCILE_VIEW(recnData->credit));
2543 std::for_each (recnData->autoclear_splits.begin(),
2544 recnData->autoclear_splits.end(),
2545 [recnData](Split* split)
2548 ? recnData->debit : recnData->credit;
2549 gnc_reconcile_view_set_cleared (GNC_RECONCILE_VIEW(view), split);
2551 recnRefresh (recnData);
2552 gnc_resume_gui_refresh ();
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
High-Level API for imposing Lot constraints.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gboolean xaccAccountGetAutoInterest(const Account *acc)
Get the "auto interest" flag for an account.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
The instance data structure for a content plugin.
Date and Time handling routines.
This file contains the functions to present a gui to the user for creating a new account or editing a...
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccAccountSetReconcileLastDate(Account *acc, time64 last_date)
DOCUMENT ME!
Functions that are supported by all types of windows.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling 'func' on each...
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
void xaccAccountSetReconcileLastInterval(Account *acc, int months, int days)
DOCUMENT ME!
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
void gnc_ui_edit_account_window(GtkWindow *parent, Account *account)
Display a window for editing the attributes of an existing account.
struct tm * gnc_localtime_r(const time64 *secs, struct tm *time)
fill out a time struct from a 64-bit time value adjusted for the current time zone.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean xaccAccountGetReconcilePostponeDate(const Account *acc, time64 *postpone_date)
DOCUMENT ME!
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
#define xaccAccountGetGUID(X)
convert single-entry accounts to clean double-entry
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Functions providing a register page for the GnuCash UI.
Account public routines (C++ api)
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome's yelp for linux, and open to a given link within a gi...
#define YREC
The Split has been reconciled.
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
void xaccAccountTreeScrubOrphans(Account *acc, QofPercentageFunc percentagefunc)
The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its childr...
void xaccAccountClearReconcilePostpone(Account *acc)
DOCUMENT ME!
The bank account type denotes a savings or checking account held at a bank.
void xaccAccountSetReconcilePostponeDate(Account *acc, time64 postpone_date)
DOCUMENT ME!
Gnome specific utility functions.
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Additional event handling code.
void xaccAccountSetReconcilePostponeBalance(Account *acc, gnc_numeric balance)
DOCUMENT ME!
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
gnc_numeric xaccAccountGetBalanceAsOfDate(Account *acc, time64 date)
Get the balance of the account at the end of the day before the date specified.
gboolean xaccAccountGetReconcileLastDate(const Account *acc, time64 *last_date)
DOCUMENT ME!
#define CREC
The Split has been cleared.
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
#define xaccTransGetGUID(X)
Generic api to store and retrieve preferences.
void gnc_add_accelerator_keys_for_menu(GtkWidget *menu, GMenuModel *model, GtkAccelGroup *accel_group)
Add accelerator keys for menu item widgets.
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
gboolean xaccAccountGetReconcileChildrenStatus(const Account *acc)
DOCUMENT ME!
gboolean xaccAccountGetReconcileLastInterval(const Account *acc, int *months, int *days)
DOCUMENT ME!
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Split * gnc_account_find_split(const Account *acc, std::function< bool(const Split *)> predicate, bool reverse)
scans account split list (in forward or reverse order) until predicate split->bool returns true...
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
time64 gnc_time64_get_day_end_gdate(const GDate *date)
The gnc_time64_get_day_end() routine will take the given time in GLib GDate format and adjust it to t...
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
time64 gnc_time(time64 *tbuf)
get the current time
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
void gnc_plugin_page_register_clear_current_filter(GncPluginPage *plugin_page)
This function clears the registers current filter.
time64 gnc_time64_get_day_end(time64 time_val)
The gnc_time64_get_day_end() routine will take the given time in seconds and adjust it to the last se...
File path resolution utility functions.
The type used to store guids in C.
GNCSplitReg * gnc_plugin_page_register_get_gsr(GncPluginPage *plugin_page)
Get the GNCSplitReg data structure associated with this register page.
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
size_t qof_print_date_buff(char *buff, size_t buflen, time64 secs)
Convenience: calls through to qof_print_date_dmy_buff().
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
void xaccAccountSetReconcileChildrenStatus(Account *acc, gboolean status)
DOCUMENT ME!
The Credit card account is used to denote credit (e.g.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
gboolean xaccAccountGetReconcilePostponeBalance(const Account *acc, gnc_numeric *balance)
DOCUMENT ME!
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...