30 #include "dialog-sx-editor.h"
31 #include "dialog-sx-from-trans.h"
32 #include "dialog-utils.h"
33 #include "gnc-component-manager.h"
34 #include "gnc-date-edit.h"
35 #include "gnc-dense-cal-store.h"
36 #include "gnc-dense-cal.h"
38 #include "engine-helpers.h"
43 #include "Recurrence.h"
46 #include "SX-ttinfo.h"
47 #include <glib/gi18n.h>
51 #define SXFTD_ERRNO_UNBALANCED_XACTION 3
52 #define SXFTD_ERRNO_OPEN_XACTION -3
54 #define SXFTD_EXCAL_NUM_MONTHS 4
55 #define SXFTD_EXCAL_MONTHS_PER_COL 4
57 #define SXFTD_RESPONSE_ADVANCED 100
60 #define G_LOG_DOMAIN GNC_MOD_GUI_SX
64 static void sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data );
65 static void gnc_sx_trans_window_response_cb(GtkDialog *dialog, gint response, gpointer data);
67 static void sxftd_destroy( GtkWidget *w, gpointer user_data );
69 typedef enum { FREQ_DAILY = 0,
83 GtkComboBox *freq_combo;
85 GtkToggleButton *ne_but;
86 GtkToggleButton *ed_but;
87 GtkToggleButton *oc_but;
88 GtkEntry *n_occurences;
108 static void sxftd_update_excal_adapt( GObject *o, gpointer ud );
128 {
"never_end_button",
"clicked", sxftd_update_excal_adapt },
129 {
"end_on_date_button",
"clicked", sxftd_update_excal_adapt },
130 {
"n_occurrences_button",
"clicked", sxftd_update_excal_adapt },
131 {
"n_occurrences_entry",
"changed", sxftd_update_excal_adapt },
138 for (i = 0; callbacks[i].name != NULL; i++)
140 w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, callbacks[i].name));
142 g_signal_connect (GTK_OBJECT(w), callbacks[i].signal,
143 G_CALLBACK(callbacks[i].handlerFn),
147 g_signal_connect (G_OBJECT(sxfti->dialog),
"response",
148 G_CALLBACK (gnc_sx_trans_window_response_cb),
158 retval.type = BAD_END;
159 g_date_clear( &(retval.end_date), 1 );
160 retval.n_occurrences = 0;
162 if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->ne_but)))
164 retval.type = NEVER_END;
168 if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->ed_but)))
171 retval.type = END_ON_DATE;
172 g_date_clear( &(retval.end_date), 1 );
173 end_tt = gnc_date_edit_get_date(sxfti->endDateGDE);
178 if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->oc_but) ))
180 gchar *text, *endptr;
183 text = gtk_editable_get_chars(GTK_EDITABLE(sxfti->n_occurences), 0, -1);
184 if (text == NULL || strlen(text) == 0)
190 n_occs = strtoul(text, &endptr, 10);
198 retval.type = END_AFTER_N_OCCS;
199 retval.n_occurrences = n_occs;
211 GList *tt_list = NULL;
212 GList *splits, *template_splits = NULL;
213 TTInfo *tti = gnc_ttinfo_malloc();
220 runningBalance = gnc_numeric_zero();
223 gnc_ttinfo_set_num(tti, gnc_get_num_action(tr, NULL));
229 ttsi = gnc_ttsplitinfo_malloc();
230 gnc_ttsplitinfo_set_action(ttsi, gnc_get_num_action(NULL, sp));
239 tmpStr = xaccPrintAmount( split_value,
240 gnc_default_print_info(FALSE) );
241 gnc_ttsplitinfo_set_debit_formula( ttsi, tmpStr );
247 gnc_default_print_info(FALSE) );
248 gnc_ttsplitinfo_set_credit_formula( ttsi, tmpStr );
254 template_splits = g_list_append(template_splits, ttsi);
258 && !gnc_verify_dialog( (GtkWidget *)sxfti->dialog,
260 _(
"The Scheduled Transaction Editor "
261 "cannot automatically balance "
263 "Should it still be "
266 return SXFTD_ERRNO_UNBALANCED_XACTION;
269 gnc_ttinfo_set_template_splits(tti, template_splits);
271 tt_list = g_list_append(tt_list, tti);
273 gnc_suspend_gui_refresh ();
275 gnc_get_current_book ());
276 gnc_resume_gui_refresh ();
283 sxftd_update_schedule(
SXFromTransInfo *sxfti, GDate *date, GList **recurrences)
290 index = gtk_combo_box_get_active(GTK_COMBO_BOX(sxfti->freq_combo));
297 recurrenceSet(r, 1, PERIOD_DAY, date, WEEKEND_ADJ_NONE);
298 *recurrences = g_list_append(*recurrences, r);
306 int mult = (index == FREQ_BIWEEKLY ? 2 : 1);
307 recurrenceSet(r, mult, PERIOD_WEEK, date, WEEKEND_ADJ_NONE);
308 *recurrences = g_list_append(*recurrences, r);
317 int mult = (index == FREQ_MONTHLY
319 : (index == FREQ_QUARTERLY
322 recurrenceSet(r, mult, PERIOD_MONTH, date, recurrenceGetWeekendAdjust(r));
323 *recurrences = g_list_append(*recurrences, r);
328 g_critical(
"nonexistent frequency selected");
338 const char *transName;
340 GList *schedule = NULL;
343 GDate date, nextDate;
349 if ( ! sxfti->trans )
355 return SXFTD_ERRNO_OPEN_XACTION;
360 sxfti->ne_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder,
"never_end_button"));
361 sxfti->ed_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder,
"end_on_date_button"));
362 sxfti->oc_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder,
"n_occurrences_button"));
363 sxfti->n_occurences = GTK_ENTRY(gtk_builder_get_object(sxfti->builder,
"n_occurrences_entry"));
370 sxfti->name = GTK_ENTRY(gtk_builder_get_object(sxfti->builder,
"name_entry" ));
372 gtk_editable_insert_text( GTK_EDITABLE(sxfti->name), transName,
373 (strlen(transName) *
sizeof(
char)), &pos );
375 sxfti_attach_callbacks(sxfti);
379 int num_marks = SXFTD_EXCAL_NUM_MONTHS * 31;
381 w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder,
"ex_cal_frame" ));
382 sxfti->dense_cal_model = gnc_dense_cal_store_new(num_marks);
383 sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(sxfti->dense_cal_model)));
384 g_object_ref_sink(sxfti->example_cal);
386 g_assert(sxfti->example_cal);
387 gnc_dense_cal_set_num_months( sxfti->example_cal, SXFTD_EXCAL_NUM_MONTHS );
388 gnc_dense_cal_set_months_per_col( sxfti->example_cal, SXFTD_EXCAL_MONTHS_PER_COL );
389 gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxfti->example_cal) );
394 GtkWidget *paramTable = GTK_WIDGET(gtk_builder_get_object(sxfti->builder,
"param_table" ));
395 sxfti->startDateGDE =
396 GNC_DATE_EDIT( gnc_date_edit_new (
gnc_time (NULL),
398 gtk_table_attach( GTK_TABLE(paramTable),
399 GTK_WIDGET( sxfti->startDateGDE ),
401 (GTK_EXPAND | GTK_FILL),
404 g_signal_connect( sxfti->startDateGDE,
"date-changed",
405 G_CALLBACK( sxftd_update_excal_adapt ),
409 GtkWidget *endDateBox = GTK_WIDGET(gtk_builder_get_object(sxfti->builder,
"end_date_hbox" ));
411 GNC_DATE_EDIT( gnc_date_edit_new (
gnc_time (NULL),
413 gtk_box_pack_start( GTK_BOX( endDateBox ),
414 GTK_WIDGET( sxfti->endDateGDE ),
416 g_signal_connect( sxfti->endDateGDE,
"date-changed",
417 G_CALLBACK( sxftd_update_excal_adapt ),
425 sxfti->freq_combo = GTK_COMBO_BOX(gtk_builder_get_object(sxfti->builder,
"freq_combo_box"));
426 gtk_combo_box_set_active(GTK_COMBO_BOX(sxfti->freq_combo), 0);
427 g_signal_connect( sxfti->freq_combo,
"changed",
428 G_CALLBACK(sxftd_freq_combo_changed),
430 sxftd_update_schedule( sxfti, &date, &schedule);
431 recurrenceListNextInstance(schedule, &date, &nextDate);
432 recurrenceListFree(&schedule);
434 gnc_date_edit_set_time( sxfti->startDateGDE, start_tt );
436 g_signal_connect( GTK_OBJECT(sxfti->name),
"destroy",
437 G_CALLBACK(sxftd_destroy),
440 sxftd_update_example_cal( sxfti );
451 GList *schedule = NULL;
453 guint sxftd_errno = 0;
458 name = gtk_editable_get_chars(GTK_EDITABLE(sxfti->name), 0, -1);
465 sxftd_update_schedule(sxfti, &date, &schedule);
466 if (sxftd_errno == 0)
469 xaccSchedXactionSetStartDate( sx, &date );
472 end_info = sxftd_get_end_info(sxfti);
474 switch (end_info.type)
483 case END_AFTER_N_OCCS:
497 gboolean autoCreateState, notifyState;
504 xaccSchedXactionSetAutoCreate( sx,
506 (autoCreateState & notifyState) );
510 xaccSchedXactionSetAdvanceCreation( sx, daysInAdvance );
514 xaccSchedXactionSetAdvanceReminder( sx, daysInAdvance );
517 if ( sxftd_add_template_trans( sxfti ) != 0 )
519 sxftd_errno = SXFTD_ERRNO_UNBALANCED_XACTION;
529 if ( sxfti->sx && delete_sx )
531 gnc_sx_begin_edit(sxfti->sx);
536 gtk_widget_destroy (GTK_WIDGET (sxfti->dialog));
545 guint sx_error = sxftd_compute_sx(sxfti);
548 && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION)
550 g_critical(
"sxftd_compute_sx after ok_clicked [%d]", sx_error);
554 if ( sx_error == SXFTD_ERRNO_UNBALANCED_XACTION )
557 _(
"The Scheduled Transaction is unbalanced. "
558 "You are strongly encouraged to correct this situation." ) );
560 book = gnc_get_current_book ();
561 sxes = gnc_book_get_schedxactions(book);
562 gnc_sxes_add_sx(sxes, sxfti->sx);
565 sxftd_close(sxfti, FALSE);
576 sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data )
579 GDate date, nextDate;
582 GList *schedule = NULL;
587 g_date_clear(&nextDate, 1);
588 sxftd_update_schedule(sxfti, &date, &schedule);
589 recurrenceListNextInstance(schedule, &date, &nextDate);
591 gnc_date_edit_set_time( sxfti->startDateGDE, tmp_tt );
593 recurrenceListFree(&schedule);
594 sxftd_update_example_cal( sxfti );
601 guint sx_error = sxftd_compute_sx(sxfti);
602 GMainContext *context;
604 if ( sx_error != 0 && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION )
608 g_warning(
"something bad happened in sxftd_compute_sx [%d]", sx_error);
611 gtk_widget_hide( sxfti->dialog );
613 context = g_main_context_default();
614 while (g_main_context_iteration(context, FALSE));
616 gnc_ui_scheduled_xaction_editor_dialog_create(sxfti->sx, TRUE );
619 sxftd_close(sxfti, FALSE);
624 sxftd_destroy( GtkWidget *w, gpointer user_data )
630 gnc_sx_begin_edit(sxfti->sx);
635 g_object_unref(G_OBJECT(sxfti->dense_cal_model));
636 g_object_unref(G_OBJECT(sxfti->example_cal));
643 gnc_sx_trans_window_response_cb (GtkDialog *dialog,
649 ENTER(
" dialog %p, response %d, sx %p", dialog, response, sxfti);
652 case GTK_RESPONSE_OK:
654 sxftd_ok_clicked(sxfti);
656 case SXFTD_RESPONSE_ADVANCED:
657 g_debug(
" ADVANCED");
658 sxftd_advanced_clicked(sxfti);
660 case GTK_RESPONSE_CANCEL:
663 sxftd_close(sxfti, TRUE);
680 GDate date, startDate, nextDate;
681 GList *schedule = NULL;
684 get = sxftd_get_end_info( sxfti );
686 tmp_tt = gnc_date_edit_get_date( sxfti->startDateGDE );
689 sxftd_update_schedule(sxfti, &date, &schedule);
694 g_date_subtract_days(&date, 1);
695 g_date_clear(&nextDate, 1);
696 recurrenceListNextInstance(schedule, &date, &nextDate);
702 name = gtk_editable_get_chars(GTK_EDITABLE(sxfti->name), 0, -1);
703 gnc_dense_cal_store_update_name(sxfti->dense_cal_model, name);
708 gchar *schedule_desc;
709 schedule_desc = recurrenceListToCompactString(schedule);
710 gnc_dense_cal_store_update_info(sxfti->dense_cal_model, schedule_desc);
711 g_free(schedule_desc);
715 gtk_widget_set_sensitive( GTK_WIDGET(sxfti->endDateGDE), (
get.type == END_ON_DATE) );
716 gtk_widget_set_sensitive( GTK_WIDGET(sxfti->n_occurences), (
get.type == END_AFTER_N_OCCS) );
721 gnc_dense_cal_store_update_recurrences_no_end(sxfti->dense_cal_model, &startDate, schedule);
724 gnc_dense_cal_store_update_recurrences_date_end(sxfti->dense_cal_model, &startDate, schedule, &
get.end_date);
726 case END_AFTER_N_OCCS:
727 gnc_dense_cal_store_update_recurrences_count_end(sxfti->dense_cal_model, &startDate, schedule,
get.n_occurrences);
730 g_warning(
"unknown get.type [%d]\n",
get.type);
734 gnc_dense_cal_set_month( sxfti->example_cal, g_date_get_month( &startDate ) );
735 gnc_dense_cal_set_year( sxfti->example_cal, g_date_get_year( &startDate ) );
737 recurrenceListFree(&schedule);
745 sxftd_update_excal_adapt( GObject *o, gpointer ud )
748 sxftd_update_example_cal( sxfti );
763 builder = gtk_builder_new();
765 gnc_builder_add_from_file (builder ,
"dialog-sx.glade",
"freq_liststore");
767 gnc_builder_add_from_file (builder ,
"dialog-sx.glade",
"sx_from_real_trans");
768 dialog = GTK_WIDGET(gtk_builder_get_object (builder,
"sx_from_real_trans"));
770 sxfti->builder = builder;
771 sxfti->dialog = dialog;
772 sxfti->trans = trans;
776 if ( (errno = sxftd_init( sxfti )) < 0 )
778 if ( errno == SXFTD_ERRNO_OPEN_XACTION )
781 _(
"Cannot create a Scheduled Transaction "
782 "from a Transaction currently "
783 "being edited. Please Enter the "
784 "Transaction before Scheduling." ) );
785 sxftd_close( sxfti, TRUE );
790 g_error(
"sxftd_init: %d", errno);
794 gtk_widget_show_all(GTK_WIDGET(sxfti->dialog));
796 gtk_builder_connect_signals(builder, sxfti);
797 g_object_unref(G_OBJECT(builder));
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
time64 xaccTransGetDate(const Transaction *trans)
gboolean xaccTransIsOpen(const Transaction *trans)
utility functions for the GnuCash UI
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
gnc_numeric gnc_numeric_neg(gnc_numeric a)
time64 gnc_time64_get_day_start_gdate(const GDate *date)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_numeric_zero_p(gnc_numeric a)
#define ENTER(format, args...)
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
const char * xaccTransGetDescription(const Transaction *trans)
void xaccSchedXactionSetTemplateTrans(SchedXaction *sx, GList *t_t_list, QofBook *book)
Set the schedxaction's template transaction.
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Generic api to store and retrieve preferences.
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
gnc_numeric xaccSplitGetValue(const Split *split)
Account * xaccSplitGetAccount(const Split *s)
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
#define LEAVE(format, args...)
time64 gnc_time(time64 *tbuf)
get the current local time
GtkWidget * gnc_ui_get_toplevel(void)
const char * xaccSplitGetMemo(const Split *split)
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Scheduled Transactions public handling routines.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
void xaccSchedXactionDestroy(SchedXaction *sx)
SplitList * xaccTransGetSplitList(const Transaction *trans)
const gchar * QofLogModule
void gnc_gdate_set_time64(GDate *gd, time64 time)
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)