38 #include <glib/gi18n.h>
47 #include "dialog-sx-editor2.h"
48 #include "dialog-utils.h"
49 #include "gnc-component-manager.h"
51 #include "gnc-date-edit.h"
52 #include "gnc-dense-cal.h"
53 #include "gnc-dense-cal-store.h"
56 #include "gnc-frequency.h"
57 #include "gnc-gui-query.h"
58 #include "gnc-hooks.h"
59 #include "gnc-ledger-display.h"
61 #include "gnc-plugin-page-register2.h"
65 #include "gnc-tree-model-split-reg.h"
66 #include "gnc-tree-control-split-reg.h"
69 #include "dialog-sx-since-last-run.h"
72 #define G_LOG_DOMAIN "gnc.gui.sx.editor"
76 static gint _sx_engine_event_handler_id = -1;
78 #define END_NEVER_OPTION 0
79 #define END_DATE_OPTION 1
80 #define NUM_OCCUR_OPTION 2
82 #define NUM_LEDGER_LINES_DEFAULT 6
84 #define EX_CAL_NUM_MONTHS 6
85 #define EX_CAL_MO_PER_COL 3
87 #define GNC_D_WIDTH 25
88 #define GNC_D_BUF_WIDTH 26
92 typedef enum _EndTypeEnum
99 typedef enum { NO_END, DATE_END, COUNT_END } END_TYPE;
105 GtkNotebook *notebook;
117 GtkEditable *nameEntry;
119 GtkLabel *lastOccurLabel;
121 GtkToggleButton *enabledOpt;
122 GtkToggleButton *autocreateOpt;
123 GtkToggleButton *notifyOpt;
124 GtkToggleButton *advanceOpt;
125 GtkSpinButton *advanceSpin;
126 GtkToggleButton *remindOpt;
127 GtkSpinButton *remindSpin;
129 GtkToggleButton *optEndDate;
130 GtkToggleButton *optEndNone;
131 GtkToggleButton *optEndCount;
132 GtkEntry *endCountSpin;
133 GtkEntry *endRemainSpin;
147 static void endgroup_rb_toggled_cb (GtkButton *b, gpointer d);
154 static void gnc_sxed_freq_changed (
GncFrequency *gf, gpointer ud);
155 static void sxed_excal_update_adapt_cb (GtkObject *o, gpointer ud);
157 static void on_sx_check_toggled_cb (GtkWidget *togglebutton, gpointer user_data);
160 static gboolean sxed_delete_event (GtkWidget *widget, GdkEvent *event, gpointer ud);
162 static gboolean editor_component_sx_equality (gpointer
find_data, gpointer user_data);
164 static GtkActionEntry gnc_sxed_menu_entries [] =
166 {
"EditAction", NULL, N_(
"_Edit"), NULL, NULL, NULL },
167 {
"TransactionAction", NULL, N_(
"_Transaction"), NULL, NULL, NULL },
168 {
"ViewAction", NULL, N_(
"_View"), NULL, NULL, NULL },
169 {
"ActionsAction", NULL, N_(
"_Actions"), NULL, NULL, NULL },
171 static guint gnc_sxed_menu_n_entries = G_N_ELEMENTS (gnc_sxed_menu_entries);
176 sxed_close_handler(gpointer user_data)
180 gnc_sxed_reg_check_close(sxed);
181 gnc_save_window_size( GNC_PREFS_GROUP_SXED, GTK_WINDOW(sxed->dialog) );
182 gtk_widget_destroy(sxed->dialog);
196 view = gnc_ledger_display2_get_split_view_register (sxed->ledger);
198 if (gnc_sxed_check_changed (sxed))
200 const char *sx_changed_msg =
201 _(
"This Scheduled Transaction has changed; are you "
202 "sure you want to cancel?" );
203 if (!gnc_verify_dialog (sxed->dialog, FALSE,
"%s", sx_changed_msg))
209 gnc_tree_view_split_reg_cancel_edit (view, TRUE);
221 if (!sxed_confirmed_cancel (sxed))
224 gnc_close_gui_component_by_data (DIALOG_SCHEDXACTION2_EDITOR_CM_CLASS,
242 if (!gnc_sxed_check_consistent (sxed))
245 gnc_sxed_save_sx (sxed);
251 book = gnc_get_current_book ();
252 sxes = gnc_book_get_schedxactions (book);
253 gnc_sxes_add_sx (sxes, sxed->sx);
254 sxed->newsxP = FALSE;
258 gnc_close_gui_component_by_data (DIALOG_SCHEDXACTION2_EDITOR_CM_CLASS,
279 name = gtk_editable_get_chars (GTK_EDITABLE (sxed->nameEntry), 0, -1);
280 if (strlen (name) == 0)
285 if ((xaccSchedXactionGetName (sxed->sx) == NULL)
286 || (strcmp( xaccSchedXactionGetName (sxed->sx),
296 if (gtk_toggle_button_get_active (sxed->optEndNone))
298 if (xaccSchedXactionHasEndDate (sxed->sx)
306 if (gtk_toggle_button_get_active (sxed->optEndDate))
308 GDate sxEndDate, dlgEndDate;
310 if (!xaccSchedXactionHasEndDate (sxed->sx))
316 gnc_date_edit_get_date( sxed->
319 if (g_date_compare (&sxEndDate, &dlgEndDate) != 0)
326 if (gtk_toggle_button_get_active (sxed->optEndCount))
328 gint sxNumOccur, sxNumRem, dlgNumOccur, dlgNumRem;
330 if (!xaccSchedXactionGetNumOccur (sxed->sx))
336 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endCountSpin));
339 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endRemainSpin));
341 sxNumOccur = xaccSchedXactionGetNumOccur (sxed->sx);
342 sxNumRem = xaccSchedXactionGetRemOccur (sxed->sx);
344 if ((dlgNumOccur != sxNumOccur)
345 || (dlgNumRem != sxNumRem))
360 gint dlgAdvance, sxAdvance;
361 gint dlgRemind, sxRemind;
364 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->
367 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->
370 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->
373 sxEnabled = xaccSchedXactionGetEnabled (sxed->sx);
374 if (!((dlgEnabled == sxEnabled)))
379 xaccSchedXactionGetAutoCreate (sxed->sx, &sxAutoCreate, &sxNotify);
380 if (!((dlgAutoCreate == sxAutoCreate)
381 && (dlgNotify == sxNotify)))
387 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->advanceOpt)))
390 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->
393 sxAdvance = xaccSchedXactionGetAdvanceCreation (sxed->sx);
394 if (dlgAdvance != sxAdvance)
400 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->remindOpt)))
403 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->remindSpin));
405 sxRemind = xaccSchedXactionGetAdvanceReminder (sxed->sx);
406 if (dlgRemind != sxRemind)
413 GList *dialog_schedule = NULL;
414 GDate dialog_start_date, sx_start_date;
415 gchar *dialog_schedule_str, *sx_schedule_str;
416 gboolean schedules_are_the_same, start_dates_are_the_same;
418 g_date_clear (&dialog_start_date, 1);
419 gnc_frequency_save_to_recurrence (sxed->gncfreq, &dialog_schedule, &dialog_start_date);
420 dialog_schedule_str = recurrenceListToString (dialog_schedule);
421 recurrenceListFree (&dialog_schedule);
423 sx_start_date = *xaccSchedXactionGetStartDate (sxed->sx);
426 g_debug (
"dialog schedule [%s], sx schedule [%s]",
427 dialog_schedule_str, sx_schedule_str);
429 schedules_are_the_same = (strcmp (dialog_schedule_str, sx_schedule_str) == 0);
430 g_free (dialog_schedule_str);
431 g_free (sx_schedule_str);
433 start_dates_are_the_same = (g_date_compare (&dialog_start_date, &sx_start_date) == 0);
435 if (!schedules_are_the_same || !start_dates_are_the_same)
443 gnc_tree_view_split_reg_finish_edit (view);
444 if (gnc_tree_view_split_reg_get_dirty_trans (view) != NULL)
464 set_sums_to_zero (gpointer key,
469 tcds->creditSum = gnc_numeric_zero();
470 tcds->debitSum = gnc_numeric_zero();
475 check_credit_debit_balance (gpointer key,
480 gboolean *unbalanced = (gboolean*)ud;
482 gnc_numeric_sub_fixed (tcds->debitSum,
490 g_debug (
"%p | true [%s - %s = %s]",
499 g_debug (
"%p | false [%s - %s = %s]",
517 gboolean multi_commodity = FALSE;
519 gint ttVarCount, splitCount;
520 GList *schedule = NULL;
544 static const int NUM_ITERS_WITH_VARS = 5;
545 static const int NUM_ITERS_NO_VARS = 1;
547 GHashTable *vars, *txns;
548 GList *splitList = NULL;
549 char *credit_formula = NULL, *debit_formula = NULL;
553 gboolean unbalanceable;
554 gpointer unusedKey, unusedValue;
556 unbalanceable = FALSE;
557 vars = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)gnc_sx_variable_free);
558 txns = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
559 numIters = NUM_ITERS_NO_VARS;
570 gnc_sx_get_variables (sxed->sx, vars);
572 ttVarCount = g_hash_table_size (vars);
584 numIters = NUM_ITERS_WITH_VARS;
587 for (i = 0; i < numIters && !unbalanceable; i++)
589 gnc_sx_randomize_variables (vars);
590 g_hash_table_foreach (txns, set_sums_to_zero, NULL);
591 tmp = gnc_numeric_zero();
593 splitList = xaccSchedXactionGetSplits (sxed->sx);
594 splitCount += g_list_length (splitList);
596 for (; splitList; splitList = splitList->next)
603 s = (
Split*)splitList->data;
611 tcds->creditSum = gnc_numeric_zero();
612 tcds->debitSum = gnc_numeric_zero();
613 g_hash_table_insert (txns, (gpointer)t, (gpointer)tcds);
617 "sx-account", &acct_guid,
618 "sx-credit-formula", &credit_formula,
619 "sx-debit-formula", &debit_formula,
623 if (base_cmdty == NULL)
625 base_cmdty = split_cmdty;
629 if ( g_strcmp0 (credit_formula,
"") != 0 &&
630 gnc_sx_parse_vars_from_formula(credit_formula, vars,
635 errStr = g_string_sized_new( 32 );
636 g_string_printf( errStr,
637 _(
"Couldn't parse credit formula for "
640 gnc_error_dialog( GTK_WIDGET(sxed->dialog),
"%s",
642 g_string_free( errStr, TRUE );
649 tmp = gnc_numeric_zero();
650 if ( g_strcmp0 (debit_formula,
"") != 0 &&
651 gnc_sx_parse_vars_from_formula( debit_formula, vars,
656 errStr = g_string_sized_new( 32 );
657 g_string_printf( errStr,
658 _(
"Couldn't parse debit formula for "
661 gnc_error_dialog( GTK_WIDGET(sxed->dialog),
"%s",
662 (gchar*)errStr->str );
663 g_string_free( errStr, TRUE );
669 tmp = gnc_numeric_zero();
672 g_hash_table_foreach (txns,
673 check_credit_debit_balance,
678 if (g_hash_table_lookup_extended (vars,
"i",
685 g_hash_table_destroy (vars);
686 g_hash_table_destroy (txns);
689 && !gnc_verify_dialog (sxed->dialog, FALSE,
691 _(
"The Scheduled Transaction Editor "
692 "cannot automatically balance "
694 "Should it still be "
704 gchar *name, *nameKey;
705 gboolean nameExists, nameHasChanged;
708 name = gtk_editable_get_chars (GTK_EDITABLE (sxed->nameEntry), 0, -1);
709 if (strlen (name) == 0 )
711 const char *sx_has_no_name_msg =
712 _(
"Please name the Scheduled Transaction.");
713 gnc_error_dialog (sxed->dialog,
"%s", sx_has_no_name_msg);
720 nameKey = g_utf8_collate_key (name, -1);
722 (xaccSchedXactionGetName (sxed->sx) == NULL)
723 || (strcmp (xaccSchedXactionGetName (sxed->sx), name) != 0);
725 gnc_book_get_schedxactions (gnc_get_current_book())->sx_list;
726 nameHasChanged && !nameExists && sxList;
727 sxList = sxList->next )
729 char *existingName, *existingNameKey;
732 existingNameKey = g_utf8_collate_key (existingName, -1);
733 nameExists |= (strcmp (nameKey, existingNameKey) == 0);
734 g_free (existingNameKey);
736 if (nameHasChanged && nameExists)
738 const char *sx_has_existing_name_msg =
739 _(
"A Scheduled Transaction with the "
740 "name \"%s\" already exists. "
741 "Are you sure you want to name "
742 "this one the same?");
743 if (!gnc_verify_dialog (sxed->dialog, FALSE,
744 sx_has_existing_name_msg,
758 gboolean autocreateState;
761 gtk_toggle_button_get_active (
762 GTK_TOGGLE_BUTTON (sxed->autocreateOpt));
764 if (((ttVarCount > 0) || multi_commodity) && autocreateState)
766 gnc_warning_dialog (sxed->dialog,
"%s",
767 _(
"Scheduled Transactions with variables "
768 "cannot be automatically created."));
774 if (autocreateState && splitCount == 0)
776 gnc_warning_dialog (sxed->dialog,
"%s",
777 _(
"Scheduled Transactions without a template "
778 "transaction cannot be automatically created."));
785 GDate startDate, endDate, nextDate;
787 if (!gtk_toggle_button_get_active (sxed->optEndDate)
788 && !gtk_toggle_button_get_active (sxed->optEndCount)
789 && !gtk_toggle_button_get_active (sxed->optEndNone) )
791 const char *sx_end_spec_msg =
792 _(
"Please provide a valid end selection.");
793 gnc_error_dialog (sxed->dialog,
"%s", sx_end_spec_msg);
797 if (gtk_toggle_button_get_active (sxed->optEndCount))
802 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endCountSpin));
805 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endRemainSpin));
809 const char *sx_occur_count_zero_msg =
810 _(
"There must be some number of occurrences.");
811 gnc_error_dialog (sxed->dialog,
"%s",
812 sx_occur_count_zero_msg);
818 const char *sx_occur_counts_wrong_msg =
819 _(
"The number of remaining occurrences "
820 "(%d) is greater than the number of "
821 "total occurrences (%d).");
822 gnc_error_dialog (sxed->dialog,
823 sx_occur_counts_wrong_msg,
830 g_date_clear (&endDate, 1);
831 if ( gtk_toggle_button_get_active(sxed->optEndDate))
834 gnc_date_edit_get_date (sxed->
838 g_date_clear (&nextDate, 1);
839 gnc_frequency_save_to_recurrence (sxed->gncfreq, &schedule, &startDate);
840 if (g_list_length (schedule) > 0)
842 g_date_subtract_days (&startDate, 1);
843 recurrenceListNextInstance (schedule, &startDate, &nextDate);
845 recurrenceListFree (&schedule);
847 if (!g_date_valid (&nextDate)
848 || (g_date_valid (&endDate) && (g_date_compare (&nextDate, &endDate) > 0)))
850 const char *invalid_sx_check_msg =
851 _(
"You have attempted to create a Scheduled "
852 "Transaction which will never run. Do you "
853 "really want to do this?");
854 if (!gnc_verify_dialog (sxed->dialog, FALSE,
855 "%s", invalid_sx_check_msg))
870 gnc_sx_begin_edit (sxed->sx);
876 name = gtk_editable_get_chars (sxed->nameEntry, 0, -1);
885 if (gtk_toggle_button_get_active (sxed->optEndDate))
889 gnc_date_edit_get_date (
890 sxed->endDateEntry));
895 else if (gtk_toggle_button_get_active (sxed->optEndCount))
901 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endCountSpin));
905 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endRemainSpin));
906 xaccSchedXactionSetRemOccur (sxed->sx, num );
908 g_date_clear (&gdate, 1);
911 else if (gtk_toggle_button_get_active (sxed->optEndNone))
914 g_date_clear (&gdate, 1);
919 g_critical (
"no valid end specified\n");
925 gboolean enabledState;
927 enabledState = gtk_toggle_button_get_active (sxed->enabledOpt);
928 xaccSchedXactionSetEnabled (sxed->sx, enabledState);
933 gboolean autocreateState, notifyState;
935 autocreateState = gtk_toggle_button_get_active (sxed->autocreateOpt);
936 notifyState = gtk_toggle_button_get_active (sxed->notifyOpt);
939 xaccSchedXactionSetAutoCreate (sxed->sx,
941 (autocreateState & notifyState));
949 if (gtk_toggle_button_get_active (sxed->advanceOpt))
952 gtk_spin_button_get_value_as_int (sxed->advanceSpin);
954 xaccSchedXactionSetAdvanceCreation (sxed->sx, daysInAdvance);
957 if (gtk_toggle_button_get_active (sxed->remindOpt))
960 gtk_spin_button_get_value_as_int (sxed->remindSpin);
962 xaccSchedXactionSetAdvanceReminder (sxed->sx, daysInAdvance);
968 GList *schedule = NULL;
970 gnc_frequency_save_to_recurrence (sxed->gncfreq, &schedule, &gdate);
973 gchar *recurrence_str = recurrenceListToCompactString (schedule);
974 g_debug(
"recurrences parsed [%s]", recurrence_str);
975 g_free (recurrence_str);
979 xaccSchedXactionSetStartDate (sxed->sx, &gdate);
982 gnc_sx_commit_edit (sxed->sx);
996 if ( !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(o)))
998 gtk_toggle_button_set_active (sxed->notifyOpt, FALSE);
1000 gtk_widget_set_sensitive (GTK_WIDGET (sxed->notifyOpt),
1001 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(o)));
1009 gtk_widget_set_sensitive(GTK_WIDGET (sxed->advanceSpin),
1010 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->advanceOpt)));
1011 gtk_editable_set_editable(GTK_EDITABLE (sxed->advanceSpin), TRUE);
1019 gtk_widget_set_sensitive (GTK_WIDGET (sxed->remindSpin),
1020 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sxed->remindOpt)));
1021 gtk_editable_set_editable (GTK_EDITABLE (sxed->remindSpin), TRUE);
1027 scheduledxaction_editor_dialog_destroy (GtkObject *
object, gpointer data)
1034 gnc_unregister_gui_component_by_data
1035 (DIALOG_SCHEDXACTION2_EDITOR_CM_CLASS, sxed);
1038 gtk_widget_destroy (GTK_WIDGET (sxed->embed_window));
1039 sxed->embed_window = NULL;
1040 sxed->plugin_page = NULL;
1041 sxed->ledger = NULL;
1043 g_free (sxed->sxGUIDstr);
1044 sxed->sxGUIDstr = NULL;
1056 gnc_sx_begin_edit (sxed->sx);
1067 sxed_delete_event (GtkWidget *widget, GdkEvent *event, gpointer ud)
1073 if (sxed->sx == NULL)
1078 if (!sxed_confirmed_cancel (sxed))
1090 gnc_ui_scheduled_xaction_editor_dialog_create2 (
SchedXaction *sx,
1094 GtkBuilder *builder;
1097 GList *dlgExists = NULL;
1099 static struct widgetSignalCallback
1104 gpointer objectData;
1107 {
"ok_button",
"clicked", editor_ok_button_clicked_cb, NULL },
1108 {
"cancel_button",
"clicked", editor_cancel_button_clicked_cb, NULL },
1109 {
"help_button",
"clicked", editor_help_button_clicked_cb, NULL },
1110 {
"rb_noend",
"toggled", endgroup_rb_toggled_cb, GINT_TO_POINTER(END_NEVER_OPTION) },
1111 {
"rb_enddate",
"toggled", endgroup_rb_toggled_cb, GINT_TO_POINTER(END_DATE_OPTION) },
1112 {
"rb_num_occur",
"toggled", endgroup_rb_toggled_cb, GINT_TO_POINTER(NUM_OCCUR_OPTION) },
1113 {
"remain_spin" ,
"value-changed", sxed_excal_update_adapt_cb, NULL },
1114 {
"enabled_opt",
"toggled", enabled_toggled_cb, NULL },
1115 {
"autocreate_opt",
"toggled", autocreate_toggled_cb, NULL },
1116 {
"advance_opt",
"toggled", advance_toggled_cb, NULL },
1117 {
"remind_opt",
"toggled", remind_toggled_cb, NULL },
1118 { NULL, NULL, NULL, NULL }
1121 dlgExists = gnc_find_gui_components (DIALOG_SCHEDXACTION2_EDITOR_CM_CLASS,
1122 editor_component_sx_equality,
1124 if (dlgExists != NULL)
1126 g_debug (
"dialog already exists; using that one.");
1128 gtk_window_present (GTK_WINDOW (sxed->dialog));
1129 g_list_free (dlgExists);
1136 sxed->newsxP = newSX;
1139 builder = gtk_builder_new();
1140 gnc_builder_add_from_file (builder,
"dialog-sx.glade",
"advance_days_adj");
1141 gnc_builder_add_from_file (builder,
"dialog-sx.glade",
"remind_days_adj");
1142 gnc_builder_add_from_file (builder,
"dialog-sx.glade",
"end_spin_adj");
1143 gnc_builder_add_from_file (builder,
"dialog-sx.glade",
"remain_spin_adj");
1144 gnc_builder_add_from_file (builder,
"dialog-sx.glade",
"Scheduled Transaction Editor");
1146 sxed->builder = builder;
1149 sxed->dialog = GTK_WIDGET (gtk_builder_get_object (builder,
"Scheduled Transaction Editor"));
1150 sxed->notebook = GTK_NOTEBOOK (gtk_builder_get_object (builder,
"editor_notebook"));
1151 sxed->nameEntry = GTK_EDITABLE (gtk_builder_get_object (builder,
"sxe_name"));
1152 sxed->enabledOpt = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"enabled_opt"));
1153 sxed->autocreateOpt = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"autocreate_opt"));
1154 sxed->notifyOpt = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"notify_opt"));
1155 sxed->advanceOpt = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"advance_opt"));
1156 sxed->advanceSpin = GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
"advance_days"));
1157 sxed->remindOpt = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"remind_opt"));
1158 sxed->remindSpin = GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
"remind_days"));
1159 sxed->lastOccurLabel = GTK_LABEL (gtk_builder_get_object (builder,
"last_occur_label"));
1160 sxed->optEndNone = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"rb_noend"));
1161 sxed->optEndDate = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"rb_enddate"));
1162 sxed->optEndCount = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
"rb_num_occur"));
1163 sxed->endCountSpin = GTK_ENTRY (gtk_builder_get_object (builder,
"end_spin"));
1164 sxed->endRemainSpin = GTK_ENTRY (gtk_builder_get_object (builder,
"remain_spin"));
1168 GtkWidget *endDateBox = GTK_WIDGET (gtk_builder_get_object (builder,
"end_date_hbox"));
1169 sxed->endDateEntry = GNC_DATE_EDIT (gnc_date_edit_new (
gnc_time (NULL),
1171 gtk_widget_show (GTK_WIDGET (sxed->endDateEntry));
1172 g_signal_connect (sxed->endDateEntry,
"date-changed",
1173 G_CALLBACK (sxed_excal_update_adapt_cb), sxed);
1174 gtk_box_pack_start (GTK_BOX (endDateBox), GTK_WIDGET (sxed->endDateEntry),
1178 gnc_register_gui_component (DIALOG_SCHEDXACTION2_EDITOR_CM_CLASS,
1183 g_signal_connect (sxed->dialog,
"delete_event",
1184 G_CALLBACK (sxed_delete_event), sxed);
1185 g_signal_connect (sxed->dialog,
"destroy",
1186 G_CALLBACK (scheduledxaction_editor_dialog_destroy),
1189 for (i = 0; widgets[i].name != NULL; i++)
1191 button = GTK_WIDGET (gtk_builder_get_object (builder, widgets[i].name));
1192 if (widgets[i].objectData != NULL)
1194 g_object_set_data (G_OBJECT (button),
"whichOneAmI",
1195 widgets[i].objectData);
1197 g_signal_connect (button, widgets[i].signal,
1198 G_CALLBACK (widgets[i].fn ), sxed);
1202 gtk_widget_set_sensitive (GTK_WIDGET (sxed->notifyOpt), FALSE );
1203 gtk_widget_set_sensitive (GTK_WIDGET (sxed->advanceSpin), FALSE );
1204 gtk_widget_set_sensitive (GTK_WIDGET (sxed->remindSpin), FALSE );
1205 gtk_widget_set_sensitive (GTK_WIDGET (sxed->endCountSpin), FALSE );
1206 gtk_widget_set_sensitive (GTK_WIDGET (sxed->endRemainSpin), FALSE );
1207 gtk_editable_set_editable (GTK_EDITABLE (sxed->advanceSpin), TRUE );
1208 gtk_editable_set_editable (GTK_EDITABLE (sxed->remindSpin), TRUE );
1211 gtk_window_set_resizable (GTK_WINDOW (sxed->dialog), TRUE);
1212 gnc_restore_window_size (GNC_PREFS_GROUP_SXED, GTK_WINDOW (sxed->dialog));
1215 schedXact_editor_create_freq_sel (sxed);
1218 schedXact_editor_create_ledger (sxed);
1221 schedXact_editor_populate (sxed);
1224 gtk_widget_show (sxed->dialog);
1225 gtk_notebook_set_current_page (GTK_NOTEBOOK (sxed->notebook), 0);
1228 gtk_widget_queue_resize (GTK_WIDGET (sxed->example_cal));
1230 gnc_ledger_display2_refresh (sxed->ledger);
1233 gtk_widget_grab_focus (GTK_WIDGET (sxed->nameEntry));
1235 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, sxed);
1236 g_object_unref (G_OBJECT (builder));
1248 b = GTK_BOX (gtk_builder_get_object (sxed->builder,
"gncfreq_hbox"));
1252 xaccSchedXactionGetStartDate (sxed->sx)));
1253 g_assert (sxed->gncfreq);
1254 g_signal_connect (sxed->gncfreq,
"changed",
1255 G_CALLBACK (gnc_sxed_freq_changed),
1257 gtk_container_add (GTK_CONTAINER (b), GTK_WIDGET (sxed->gncfreq) );
1259 b = GTK_BOX(gtk_builder_get_object (sxed->builder,
"example_cal_hbox" ));
1260 sxed->dense_cal_model = gnc_dense_cal_store_new (EX_CAL_NUM_MONTHS * 31);
1261 sxed->example_cal = GNC_DENSE_CAL (gnc_dense_cal_new_with_model (GNC_DENSE_CAL_MODEL (sxed->dense_cal_model)));
1262 g_assert (sxed->example_cal);
1263 gnc_dense_cal_set_num_months (sxed->example_cal, EX_CAL_NUM_MONTHS);
1264 gnc_dense_cal_set_months_per_col( sxed->example_cal, EX_CAL_MO_PER_COL);
1265 gtk_container_add (GTK_CONTAINER (b), GTK_WIDGET (sxed->example_cal));
1266 gtk_widget_show (GTK_WIDGET (sxed->example_cal));
1275 GtkWidget *main_vbox;
1280 sxed->ledger = gnc_ledger_display2_template_gl (sxed->sxGUIDstr);
1281 model = gnc_ledger_display2_get_split_model_register (sxed->ledger);
1284 main_vbox = GTK_WIDGET (gtk_builder_get_object (sxed->builder,
"register_vbox" ));
1285 sxed->embed_window =
1287 gnc_sxed_menu_entries,
1288 gnc_sxed_menu_n_entries,
1289 "gnc-sxed-window-ui.xml",
1294 gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (sxed->embed_window), TRUE, TRUE, 0);
1296 label = gtk_label_new (_(
"Note: If you have already accepted changes to the Template, Cancel will not revoke them."));
1297 gtk_box_pack_end (GTK_BOX (main_vbox), GTK_WIDGET (label), FALSE, TRUE, 0);
1298 gtk_widget_show (label);
1303 "gnc-sxed-window-ui-full.xml");
1305 NUM_LEDGER_LINES_DEFAULT, FALSE );
1311 gnc_tree_model_split_reg_config (model, model->
type, model->
style, TRUE);
1326 gboolean enabledState, autoCreateState, notifyState;
1328 name = xaccSchedXactionGetName (sxed->sx);
1331 gtk_entry_set_text (GTK_ENTRY (sxed->nameEntry), name);
1334 gd = xaccSchedXactionGetLastOccurDate (sxed->sx);
1335 if (g_date_valid (gd))
1339 gtk_label_set_text (sxed->lastOccurLabel, dateBuf);
1343 gtk_label_set_text (sxed->lastOccurLabel, _(
"(never)"));
1349 if ( g_date_valid (gd))
1351 gtk_toggle_button_set_active (sxed->optEndDate, TRUE);
1353 gnc_date_edit_set_time (sxed->endDateEntry, tmpDate);
1355 set_endgroup_toggle_states (sxed, END_DATE);
1359 gint numOccur = xaccSchedXactionGetNumOccur (sxed->sx);
1360 gint numRemain = xaccSchedXactionGetRemOccur (sxed->sx);
1362 gtk_toggle_button_set_active (sxed->optEndCount, TRUE);
1364 gtk_spin_button_set_value (GTK_SPIN_BUTTON (sxed->endCountSpin), numOccur);
1365 gtk_spin_button_set_value (GTK_SPIN_BUTTON (sxed->endRemainSpin), numRemain);
1367 set_endgroup_toggle_states (sxed, END_OCCUR);
1371 gtk_toggle_button_set_active (sxed->optEndNone, TRUE);
1372 set_endgroup_toggle_states (sxed, END_NEVER);
1375 enabledState = xaccSchedXactionGetEnabled (sxed->sx);
1376 gtk_toggle_button_set_active (sxed->enabledOpt, enabledState);
1388 xaccSchedXactionGetAutoCreate (sxed->sx,
1392 gtk_toggle_button_set_active (sxed->autocreateOpt, autoCreateState);
1393 if (!autoCreateState)
1395 notifyState = FALSE;
1397 gtk_toggle_button_set_active( sxed->notifyOpt, notifyState );
1408 xaccSchedXactionGetAdvanceCreation (sxed->sx);
1410 if (daysInAdvance != 0)
1412 gtk_toggle_button_set_active (sxed->advanceOpt, TRUE);
1413 gtk_spin_button_set_value (sxed->advanceSpin,
1414 (gfloat)daysInAdvance);
1426 xaccSchedXactionGetAdvanceReminder (sxed->sx);
1428 if (daysInAdvance != 0)
1430 gtk_toggle_button_set_active (sxed->remindOpt, TRUE);
1431 gtk_spin_button_set_value (sxed->remindSpin,
1432 (gfloat)daysInAdvance);
1445 splitList = xaccSchedXactionGetSplits (sxed->sx);
1446 if (splitList != NULL)
1448 model = gnc_ledger_display2_get_split_model_register (sxed->ledger);
1449 gnc_tree_model_split_reg_load (model, splitList, NULL );
1454 gnc_sxed_update_cal (sxed);
1462 gtk_widget_set_sensitive (GTK_WIDGET (sxed->endDateEntry), (type == END_DATE) );
1463 gtk_widget_set_sensitive (GTK_WIDGET (sxed->endCountSpin), (type == END_OCCUR) );
1464 gtk_widget_set_sensitive (GTK_WIDGET (sxed->endRemainSpin), (type == END_OCCUR) );
1470 endgroup_rb_toggled_cb (GtkButton *b, gpointer d)
1477 id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (b),
"whichOneAmI"));
1481 case END_NEVER_OPTION:
1482 set_endgroup_toggle_states (sxed, END_NEVER);
1484 case END_DATE_OPTION:
1485 set_endgroup_toggle_states (sxed, END_DATE);
1487 case NUM_OCCUR_OPTION:
1488 set_endgroup_toggle_states (sxed, END_OCCUR);
1491 g_critical (
"Unknown id %d",
id);
1494 gnc_sxed_update_cal (sxed);
1510 const char *message =
1511 _(
"The current template transaction "
1512 "has been changed. "
1513 "Would you like to record the changes?");
1515 view = gnc_ledger_display2_get_split_view_register (sxed->ledger);
1517 dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
1519 if (dirty_trans == NULL)
1522 if (gnc_verify_dialog (sxed->dialog, TRUE,
"%s", message))
1526 gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
1532 gnc_tree_view_split_reg_cancel_edit (view, TRUE);
1538 editor_component_sx_equality (gpointer
find_data,
1551 GList *recurrences = NULL;
1552 GDate start_date, first_date;
1554 g_date_clear (&start_date, 1);
1556 gnc_frequency_save_to_recurrence (sxed->gncfreq, &recurrences, &start_date);
1557 g_date_subtract_days (&start_date, 1);
1558 recurrenceListNextInstance (recurrences, &start_date, &first_date);
1563 const GDate *last_sx_inst;
1565 last_sx_inst = xaccSchedXactionGetLastOccurDate (sxed->sx);
1566 if (g_date_valid (last_sx_inst)
1567 && g_date_valid (&first_date)
1568 && g_date_compare (last_sx_inst, &first_date) != 0)
1570 start_date = *last_sx_inst;
1571 recurrenceListNextInstance (recurrences, &start_date, &first_date);
1575 if (!g_date_valid (&first_date))
1578 gnc_dense_cal_store_clear (sxed->dense_cal_model);
1582 gnc_dense_cal_store_update_name (sxed->dense_cal_model, xaccSchedXactionGetName (sxed->sx));
1584 gchar *schedule_desc = recurrenceListToCompactString (recurrences);
1585 gnc_dense_cal_store_update_info (sxed->dense_cal_model, schedule_desc);
1586 g_free (schedule_desc);
1593 if (gtk_toggle_button_get_active (sxed->optEndDate))
1596 g_date_clear (&end_date, 1);
1598 gnc_dense_cal_store_update_recurrences_date_end (sxed->dense_cal_model, &first_date, recurrences, &end_date);
1600 else if (gtk_toggle_button_get_active (sxed->optEndNone))
1602 gnc_dense_cal_store_update_recurrences_no_end (sxed->dense_cal_model, &first_date, recurrences);
1604 else if (gtk_toggle_button_get_active (sxed->optEndCount))
1607 = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sxed->endRemainSpin));
1608 gnc_dense_cal_store_update_recurrences_count_end (sxed->dense_cal_model, &first_date, recurrences, num_remain);
1612 g_error (
"unknown end condition");
1616 recurrenceListFree (&recurrences);
1628 sxed_excal_update_adapt_cb (GtkObject *o, gpointer ud)
1635 on_sx_check_toggled_cb (GtkWidget *togglebutton, gpointer user_data)
1637 GtkWidget *widget_notify;
1640 PINFO(
"Togglebutton is %p and user_data is %p", togglebutton, user_data);
1641 PINFO(
"Togglebutton builder name is %s", gtk_buildable_get_name (GTK_BUILDABLE (togglebutton)));
1644 table = g_object_get_data(G_OBJECT(user_data),
"prefs_widget_hash");
1645 widget_notify = g_hash_table_lookup(table,
"pref/" GNC_PREFS_GROUP_SXED
"/" GNC_PREF_NOTIFY);
1647 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1648 gtk_widget_set_sensitive (widget_notify, TRUE);
1650 gtk_widget_set_sensitive (widget_notify, FALSE);
1659 GList *affected_sxes;
1665 _open_editors (GtkDialog *dialog, gint response_code, gpointer data)
1668 gtk_widget_hide (adhd->dialog);
1671 for (sx_iter = adhd->affected_sxes; sx_iter; sx_iter = sx_iter->next)
1673 gnc_ui_scheduled_xaction_editor_dialog_create2 ((
SchedXaction*)sx_iter->data,
1677 g_list_free (adhd->affected_sxes);
1678 gtk_widget_destroy (GTK_WIDGET (adhd->dialog));
1684 _sx_engine_event_handler (
QofInstance *ent,
QofEventId event_type, gpointer user_data, gpointer evt_data)
1688 GList *affected_sxes;
1690 if (!(event_type & QOF_EVENT_DESTROY))
1692 if (!GNC_IS_ACCOUNT(ent))
1694 acct = GNC_ACCOUNT(ent);
1698 if (g_list_length (affected_sxes) == 0)
1704 GtkBuilder *builder;
1706 GtkListStore *name_list;
1708 GtkTreeViewColumn *name_column;
1709 GtkCellRenderer *renderer;
1711 builder = gtk_builder_new();
1712 gnc_builder_add_from_file (builder,
"dialog-sx.glade",
"Account Deletion");
1714 dialog = GTK_WIDGET (gtk_builder_get_object (builder,
"Account Deletion"));
1716 list = GTK_TREE_VIEW (gtk_builder_get_object (builder,
"sx_list"));
1719 data->dialog = dialog;
1720 data->affected_sxes = affected_sxes;
1721 name_list = gtk_list_store_new (1, G_TYPE_STRING);
1722 for (sx_iter = affected_sxes; sx_iter != NULL; sx_iter = sx_iter->next)
1729 sx_name = xaccSchedXactionGetName (sx);
1730 gtk_list_store_append (name_list, &iter);
1731 gtk_list_store_set (name_list, &iter, 0, sx_name, -1);
1733 gtk_tree_view_set_model (list, GTK_TREE_MODEL (name_list));
1734 g_object_unref (G_OBJECT (name_list));
1736 renderer = gtk_cell_renderer_text_new();
1737 name_column = gtk_tree_view_column_new_with_attributes (_(
"Name"),
1740 gtk_tree_view_append_column (list, name_column);
1742 g_signal_connect (G_OBJECT (dialog),
"response",
1743 G_CALLBACK (_open_editors), data);
1745 gtk_widget_show_all (GTK_WIDGET (dialog));
1746 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, data);
1747 g_object_unref (G_OBJECT (builder));
1753 gnc_ui_sx_initialize2 (
void)
1757 gnc_hook_add_dangler (HOOK_BOOK_OPENED,
1758 (GFunc)gnc_sx_sxsincelast_book_opened, NULL);
1763 "create_days_adj,remind_days_adj,sx_prefs",
1764 _(
"Scheduled Transactions"));
const GDate * xaccSchedXactionGetEndDate(const SchedXaction *sx)
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
GList * gnc_sx_get_schedule(const SchedXaction *sx)
void gnc_preferences_add_page(const gchar *filename, const gchar *widgetname, const gchar *tabname)
void gnc_plugin_page_register2_set_options(GncPluginPage *plugin_page, gint lines_default, gboolean read_only)
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
GncEmbeddedWindow * gnc_embedded_window_new(const gchar *action_group_name, GtkActionEntry *action_entries, gint n_action_entries, const gchar *ui_filename, GtkWidget *enclosing_win, gboolean add_accelerators, gpointer user_data)
Date and Time handling routines.
QofBook * qof_instance_get_book(gconstpointer)
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
void gnc_embedded_window_close_page(GncEmbeddedWindow *window, GncPluginPage *page)
time64 gnc_time64_get_day_start_gdate(const GDate *date)
void gnc_plugin_page_set_ui_description(GncPluginPage *page, const char *ui_filename)
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
void gnc_embedded_window_open_page(GncEmbeddedWindow *window, GncPluginPage *page)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_numeric_zero_p(gnc_numeric a)
Transaction * xaccSplitGetParent(const Split *split)
gchar * gnc_numeric_to_string(gnc_numeric n)
GList * gnc_sx_get_sxes_referencing_account(QofBook *book, Account *acct)
gint qof_event_register_handler(QofEventHandler handler, gpointer handler_data)
Register a handler for events.
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level)
Account handling public routines.
GncPluginPage * gnc_plugin_page_register2_new_ledger(GNCLedgerDisplay2 *ledger)
SplitRegisterStyle2 style
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
Functions for adding plugins to a GnuCash window.
void xaccTransCommitEdit(Transaction *trans)
Dialog for handling user preferences.
#define xaccSchedXactionGetGUID(X)
void gnc_gnome_help(const char *file_name, const char *anchor)
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
gchar * guid_to_string(const GncGUID *guid)
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Functions that are supported by all types of windows.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
time64 gnc_time(time64 *tbuf)
get the current local time
const char * xaccSplitGetMemo(const Split *split)
gboolean xaccSchedXactionHasOccurDef(const SchedXaction *sx)
Scheduled Transactions public handling routines.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
void xaccSchedXactionDestroy(SchedXaction *sx)
size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd)
const gchar * QofLogModule
void gnc_gdate_set_time64(GDate *gd, time64 time)
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)