static Recurrence* _get_day_of_month_recurrence(GncFrequency *gf, GDate *start_date, int multiplier, char *combo_name, char *combo_weekend_name) { Recurrence *r; GtkWidget *day_of_month_combo = glade_xml_get_widget(gf->gxml, combo_name); int day_of_month_index = gtk_combo_box_get_active(GTK_COMBO_BOX(day_of_month_combo)); GtkWidget *weekend_adjust_combo = glade_xml_get_widget(gf->gxml, combo_weekend_name); int weekend_adjust = gtk_combo_box_get_active(GTK_COMBO_BOX(weekend_adjust_combo)); GDateWeekday selected_day_of_week; GDate *day_of_week_date; int selected_index, selected_week; r = g_new0(Recurrence, 1); if (day_of_month_index > LAST_DAY_OF_MONTH_OPTION_INDEX + 7) { selected_index = day_of_month_index - LAST_DAY_OF_MONTH_OPTION_INDEX - 7; day_of_week_date = g_date_new_julian(g_date_get_julian(start_date)); selected_week = (selected_index - 1) / 7 == 4 ? 3 : (selected_index - 1) / 7; selected_day_of_week = selected_index - 7 * selected_week; g_date_set_day(day_of_week_date, 1); while (g_date_get_weekday(day_of_week_date) != selected_day_of_week) g_date_add_days(day_of_week_date, 1); g_date_add_days(day_of_week_date, 7 * selected_week); recurrenceSet(r, multiplier, PERIOD_NTH_WEEKDAY, day_of_week_date, WEEKEND_ADJ_NONE); } else if (day_of_month_index > LAST_DAY_OF_MONTH_OPTION_INDEX) { day_of_week_date = g_date_new_julian(g_date_get_julian(start_date)); selected_day_of_week = day_of_month_index - LAST_DAY_OF_MONTH_OPTION_INDEX; // increment until we align on the DOW, but stay inside the month g_date_set_day(day_of_week_date, 1); while (g_date_get_weekday(day_of_week_date) != selected_day_of_week) g_date_add_days(day_of_week_date, 1); recurrenceSet(r, multiplier, PERIOD_LAST_WEEKDAY, day_of_week_date, weekend_adjust); } else if (day_of_month_index == LAST_DAY_OF_MONTH_OPTION_INDEX) { GDate *day_of_month = g_date_new_julian(g_date_get_julian(start_date)); recurrenceSet(r, multiplier, PERIOD_END_OF_MONTH, day_of_month, weekend_adjust); } else { int allowable_date = -1; GDate *day_of_month = g_date_new_julian(g_date_get_julian(start_date)); allowable_date = MIN(day_of_month_index + 1, g_date_get_days_in_month(g_date_get_month(day_of_month), g_date_get_year(day_of_month))); g_date_set_day(day_of_month, allowable_date); recurrenceSet(r, multiplier, PERIOD_MONTH, day_of_month, weekend_adjust); } return r; }
static void sxftd_update_schedule( SXFromTransInfo *sxfti, GDate *date, GList **recurrences) { gint index; GtkWidget *w; /* Note that we make the start date the *NEXT* instance, not the * present one. */ w = glade_xml_get_widget(sxfti->gxml, SXFTD_FREQ_COMBO_BOX); index = gtk_combo_box_get_active(GTK_COMBO_BOX(w)); switch (index) { case FREQ_DAILY: { Recurrence *r = g_new0(Recurrence, 1); recurrenceSet(r, 1, PERIOD_DAY, date, WEEKEND_ADJ_NONE); *recurrences = g_list_append(*recurrences, r); } break; case FREQ_WEEKLY: case FREQ_BIWEEKLY: { Recurrence *r = g_new0(Recurrence, 1); int mult = (index == FREQ_BIWEEKLY ? 2 : 1); recurrenceSet(r, mult, PERIOD_WEEK, date, WEEKEND_ADJ_NONE); *recurrences = g_list_append(*recurrences, r); } break; case FREQ_MONTHLY: case FREQ_QUARTERLY: case FREQ_ANNUALLY: { Recurrence *r = g_new0(Recurrence, 1); int mult = (index == FREQ_MONTHLY ? 1 : (index == FREQ_QUARTERLY ? 3 : 12)); recurrenceSet(r, mult, PERIOD_MONTH, date, recurrenceGetWeekendAdjust(r)); *recurrences = g_list_append(*recurrences, r); } break; default: g_critical("nonexistent frequency selected"); break; } }
static void test_specific(PeriodType pt, guint16 mult, GDateMonth sm, GDateDay sd, GDateYear sy, GDateMonth rm, GDateDay rd, GDateYear ry, GDateMonth nm, GDateDay nd, GDateYear ny) { GDate start; GDate ref, next, true_next; Recurrence r; g_date_set_dmy(&start, sd, sm, sy); g_date_set_dmy(&ref, rd, rm, ry); g_date_set_dmy(&true_next, nd, nm, ny); recurrenceSet(&r, mult, pt, &start, WEEKEND_ADJ_NONE); recurrenceNextInstance(&r, &ref, &next); check_valid(&next, &ref, &start, mult, pt, WEEKEND_ADJ_NONE); if (!test_equal(&next, &true_next)) { gchar s1[21], s2[21], s3[21]; g_date_strftime(s1, 20, "%x", &start); g_date_strftime(s2, 20, "%x", &ref); g_date_strftime(s3, 20, "%x", &true_next); printf("pt = %d; mult = %d; start = %s; ref = %s; true_next = %s\n", pt, mult, s1, s2, s3); } }
static void _fixup_recurrence_start_dates(const GDate *sx_start_date, GList *schedule) { GList *iter; for (iter = schedule; iter != NULL; iter = iter->next) { Recurrence *r; GDate start, next; r = (Recurrence*)iter->data; start = *sx_start_date; g_date_subtract_days(&start, 1); g_date_clear(&next, 1); recurrenceNextInstance(r, &start, &next); g_return_if_fail(g_date_valid(&next)); { gchar date_str[128]; gchar *sched_str; g_date_strftime(date_str, 127, "%x", &next); sched_str = recurrenceToString(r); g_debug("setting recurrence [%s] start date to [%s]", sched_str, date_str); g_free(sched_str); } recurrenceSet(r, recurrenceGetMultiplier(r), recurrenceGetPeriodType(r), &next, recurrenceGetWeekendAdjust(r)); } if (g_list_length(schedule) == 1 && recurrenceGetPeriodType((Recurrence*)g_list_nth_data(schedule, 0)) == PERIOD_ONCE) { char date_buf[128]; Recurrence *fixup = (Recurrence*)g_list_nth_data(schedule, 0); g_date_strftime(date_buf, 127, "%x", sx_start_date); recurrenceSet(fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE); g_debug("fixed up period=ONCE Recurrence to date [%s]", date_buf); } }
static void gnc_recurrence_init( GncRecurrence *gr ) { GtkVBox *vb; GtkHBox *hb; GtkWidget *w; GtkBuilder *builder; recurrenceSet(&gr->recurrence, 1, PERIOD_MONTH, NULL, WEEKEND_ADJ_NONE); /* Open up the builder file */ builder = gtk_builder_new(); gnc_builder_add_from_file (builder, "gnc-recurrence.glade", "GCB_PeriodType_liststore"); gnc_builder_add_from_file (builder, "gnc-recurrence.glade", "GSB_Mult_Adj"); gnc_builder_add_from_file (builder, "gnc-recurrence.glade", "RecurrenceEntryVBox"); vb = GTK_VBOX(gtk_builder_get_object (builder, "RecurrenceEntryVBox")); hb = GTK_HBOX(gtk_builder_get_object (builder, "Startdate_hbox")); w = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE); gr->gde_start = w; gtk_box_pack_start (GTK_BOX (hb), w, TRUE, TRUE, 0); gtk_widget_show (w); gtk_widget_set_no_show_all(GTK_WIDGET(gr->gde_start), TRUE); gr->gcb_period = GTK_COMBO_BOX(gtk_builder_get_object (builder, "GCB_PeriodType")); gr->gsb_mult = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "GSB_Mult")); gr->gcb_eom = GTK_CHECK_BUTTON(gtk_builder_get_object (builder, "GCB_EndOfMonth")); gr->nth_weekday = GTK_CHECK_BUTTON(gtk_builder_get_object (builder, "GCB_NthWeekday")); gtk_widget_set_no_show_all(GTK_WIDGET(gr->gcb_eom), TRUE); gtk_widget_set_no_show_all(GTK_WIDGET(gr->nth_weekday), TRUE); gtk_container_add( GTK_CONTAINER(&gr->widget), GTK_WIDGET(vb) ); gnc_recurrence_set(gr, &gr->recurrence); something_changed( GTK_WIDGET(gr), gr); /* Setup the signals */ g_signal_connect( G_OBJECT(gr->gde_start), "date_changed", G_CALLBACK(something_changed), gr ); g_signal_connect( G_OBJECT(gr->gcb_period), "changed", G_CALLBACK(something_changed), gr ); g_signal_connect( G_OBJECT(gr->gsb_mult), "value-changed", G_CALLBACK(something_changed), gr ); g_signal_connect( G_OBJECT(gr->gcb_eom), "toggled", G_CALLBACK(something_changed), gr ); g_signal_connect( G_OBJECT(gr->nth_weekday), "toggled", G_CALLBACK(something_changed), gr ); gtk_widget_show_all( GTK_WIDGET(&gr->widget) ); gtk_builder_connect_signals(builder, gr); g_object_unref(G_OBJECT(builder)); }
static void gnc_plugin_page_sx_list_cmd_new(GtkAction *action, GncPluginPageSxList *page) { SchedXaction *new_sx; gboolean new_sx_flag = TRUE; new_sx = xaccSchedXactionMalloc(gnc_get_current_book()); { GDate now; Recurrence *r = new Recurrence;//g_new0(Recurrence, 1); g_date_clear(&now, 1); gnc_gdate_set_today (&now); recurrenceSet(r, 1, PERIOD_MONTH, &now, WEEKEND_ADJ_NONE); RecurrenceList_t schedule = gnc_sx_get_schedule(new_sx); schedule.push_back(r); gnc_sx_set_schedule(new_sx, schedule); } gnc_ui_scheduled_xaction_editor_dialog_create(new_sx, new_sx_flag); }
/* Mult of zero is usually not valid, but it gets regularized to 1, so the effect is just that we end up testing mult of 1 twice, plus the regularization. */ static void test_all() { Recurrence r; GDate d_start, d_start_reg; GDate d_ref, d_next; guint16 mult, mult_reg; PeriodType pt, pt_reg; WeekendAdjust wadj, wadj_reg; gint32 j1, j2; gint i_ref; for (pt = PERIOD_ONCE; pt < NUM_PERIOD_TYPES; pt++) { for (wadj = WEEKEND_ADJ_NONE; wadj < NUM_WEEKEND_ADJS; wadj++) { for (j1 = JULIAN_START; j1 < JULIAN_START + NUM_DATES_TO_TEST; j1++) { g_date_set_julian(&d_start, j1); for (i_ref = 0; i_ref < NUM_DATES_TO_TEST_REF; i_ref++) { j2 = (guint32) get_random_int_in_range(1, 1 << 19); g_date_set_julian(&d_ref, j2); for (mult = 0; mult < NUM_MULT_TO_TEST; mult++) { recurrenceSet(&r, mult, pt, &d_start, wadj); pt_reg = recurrenceGetPeriodType(&r); d_start_reg = recurrenceGetDate(&r); mult_reg = recurrenceGetMultiplier(&r); wadj_reg = recurrenceGetWeekendAdjust(&r); recurrenceNextInstance(&r, &d_ref, &d_next); check_valid(&d_next, &d_ref, &d_start_reg, mult_reg, pt_reg, wadj_reg); } } } } } }
void gnc_frequency_save_to_recurrence(GncFrequency *gf, GList **recurrences, GDate *out_start_date) { GDate start_date; gint page_index; gnc_date_edit_get_gdate(gf->startDate, &start_date); if (out_start_date != NULL) *out_start_date = start_date; if (recurrences == NULL) return; page_index = gtk_notebook_get_current_page(gf->nb); switch (page_index) { case PAGE_NONE: { // empty-recurrence list ~~ none. } break; case PAGE_ONCE: { Recurrence *r = g_new0(Recurrence, 1); recurrenceSet(r, 1, PERIOD_ONCE, &start_date, WEEKEND_ADJ_NONE); *recurrences = g_list_append(*recurrences, r); } break; case PAGE_DAILY: { gint multiplier = _get_multiplier_from_widget(gf, "daily_spin"); Recurrence *r = g_new0(Recurrence, 1); recurrenceSet(r, multiplier, PERIOD_DAY, &start_date, WEEKEND_ADJ_NONE); *recurrences = g_list_append(*recurrences, r); } break; case PAGE_WEEKLY: { int multiplier = _get_multiplier_from_widget(gf, "weekly_spin"); int checkbox_idx; for (checkbox_idx = 0; CHECKBOX_NAMES[checkbox_idx] != NULL; checkbox_idx++) { GDate *day_of_week_aligned_date; Recurrence *r; const char *day_widget_name = CHECKBOX_NAMES[checkbox_idx]; GtkWidget *weekday_checkbox = glade_xml_get_widget(gf->gxml, day_widget_name); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(weekday_checkbox))) continue; day_of_week_aligned_date = g_date_new_julian(g_date_get_julian(&start_date)); // increment until we align on the DOW. while ((g_date_get_weekday(day_of_week_aligned_date) % 7) != checkbox_idx) g_date_add_days(day_of_week_aligned_date, 1); r = g_new0(Recurrence, 1); recurrenceSet(r, multiplier, PERIOD_WEEK, day_of_week_aligned_date, WEEKEND_ADJ_NONE); *recurrences = g_list_append(*recurrences, r); } } break; case PAGE_SEMI_MONTHLY: { int multiplier = _get_multiplier_from_widget(gf, "semimonthly_spin"); *recurrences = g_list_append(*recurrences, _get_day_of_month_recurrence(gf, &start_date, multiplier, "semimonthly_first", "semimonthly_first_weekend")); *recurrences = g_list_append(*recurrences, _get_day_of_month_recurrence(gf, &start_date, multiplier, "semimonthly_second", "semimonthly_second_weekend")); } break; case PAGE_MONTHLY: { int multiplier = _get_multiplier_from_widget(gf, "monthly_spin"); Recurrence *r = _get_day_of_month_recurrence(gf, &start_date, multiplier, "monthly_day", "monthly_weekend"); *recurrences = g_list_append(*recurrences, r); } break; default: g_error("unknown page index [%d]", page_index); break; } }
static GtkWidget * ap_assistant_create (AcctPeriodInfo *info) { GtkBuilder *builder; GtkWidget *window; GtkWidget *box; builder = gtk_builder_new(); gnc_builder_add_from_file (builder , "assistant-acct-period.glade", "account_period_assistant"); window = GTK_WIDGET(gtk_builder_get_object (builder, "account_period_assistant")); info->window = window; // Set the style context for this assistant so it can be easily manipulated with css gnc_widget_set_style_context (GTK_WIDGET(window), "GncAssistAccountPeriod"); /* Enable all pages except menu page. */ gtk_assistant_set_page_complete (GTK_ASSISTANT (window), GTK_WIDGET(gtk_builder_get_object(builder, "start_page")), TRUE); gtk_assistant_set_page_complete (GTK_ASSISTANT (window), GTK_WIDGET(gtk_builder_get_object(builder, "book_page")), TRUE); gtk_assistant_set_page_complete (GTK_ASSISTANT (window), GTK_WIDGET(gtk_builder_get_object(builder, "finish_page")), TRUE); gtk_assistant_set_page_complete (GTK_ASSISTANT (window), GTK_WIDGET(gtk_builder_get_object(builder, "summary_page")), TRUE); info->close_status = -1; /* Find the date of the earliest transaction in the book. * Add a year minus a day as the first guess for book closing, * and use that to set up the freq spec widget. */ info->earliest = get_earliest_in_book (gnc_get_current_book()); info->earliest_str = qof_print_date(info->earliest); PINFO ("date of earliest transaction is %" G_GINT64_FORMAT " %s", info->earliest, gnc_ctime (&info->earliest)); g_date_clear (&info->closing_date, 1); gnc_gdate_set_time64 (&info->closing_date, info->earliest); g_date_clear (&info->prev_closing_date, 1); info->prev_closing_date = info->closing_date; g_date_add_years (&info->closing_date, 1); { Recurrence *r = g_new0(Recurrence, 1); recurrenceSet(r, 1, PERIOD_MONTH, &info->closing_date, WEEKEND_ADJ_NONE); info->period = NULL; info->period = g_list_append(info->period, r); } info->period_menu = GNC_FREQUENCY( gnc_frequency_new_from_recurrence(info->period, &info->closing_date)); /* Change the text so that its more mainingful for this assistant */ gnc_frequency_set_frequency_label_text(info->period_menu, _("Period:")); gnc_frequency_set_date_label_text(info->period_menu, _("Closing Date:")); /* Reparent to the correct location */ box = GTK_WIDGET(gtk_builder_get_object(builder, "period_hbox")); gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (info->period_menu), TRUE, TRUE, 0); g_signal_connect (info->period_menu, "changed", G_CALLBACK (ap_assistant_menu_changed_cb), info); /* Get handles to all of the other widgets we'll need */ info->period_remarks = GTK_WIDGET(gtk_builder_get_object(builder, "remarks_label")); info->close_results = GTK_WIDGET(gtk_builder_get_object(builder, "results_label")); info->book_details = GTK_WIDGET(gtk_builder_get_object(builder, "book_label")); info->book_title = GTK_WIDGET(gtk_builder_get_object(builder, "book_title_entry")); info->book_notes = GTK_TEXT_VIEW(gtk_builder_get_object(builder, "book_notes_view")); info->apply_label = GTK_WIDGET(gtk_builder_get_object(builder, "finish_page")); info->summary = GTK_WIDGET(gtk_builder_get_object(builder, "summary_label")); g_signal_connect (G_OBJECT(window), "destroy", G_CALLBACK (ap_assistant_destroy_cb), info); gtk_builder_connect_signals(builder, info); g_object_unref(G_OBJECT(builder)); return window; }
static void ap_druid_create (AcctPeriodInfo *info) { GladeXML *xml; GtkWidget *w; xml = gnc_glade_xml_new ("acctperiod.glade", "Acct Period Druid"); info->window = glade_xml_get_widget (xml, "Acct Period Druid"); info->druid = GNOME_DRUID (glade_xml_get_widget (xml, "acct_period_druid")); gnc_druid_set_colors (info->druid); info->start_page = GNOME_DRUID_PAGE(glade_xml_get_widget (xml, "start page")); info->menu_page = GNOME_DRUID_PAGE(glade_xml_get_widget (xml, "menu page")); info->book_page = GNOME_DRUID_PAGE(glade_xml_get_widget (xml, "book page")); info->finish_page = GNOME_DRUID_PAGE(glade_xml_get_widget (xml, "finish page")); info->close_status = -1; /* Find the date of the earliest transaction in the book. * Add a year minus a day as the first guess for book closing, * and use that to set up the freq spec widget. */ info->earliest = get_earliest_in_book (gnc_get_current_book()); info->earliest_str = qof_print_date(info->earliest); PINFO ("date of earliest transaction is %ld %s", info->earliest, ctime (&info->earliest)); g_date_clear (&info->closing_date, 1); g_date_set_time_t (&info->closing_date, info->earliest); g_date_clear (&info->prev_closing_date, 1); info->prev_closing_date = info->closing_date; g_date_add_years (&info->closing_date, 1); { Recurrence *r = g_new0(Recurrence, 1); recurrenceSet(r, 1, PERIOD_MONTH, &info->closing_date, WEEKEND_ADJ_NONE); info->period = NULL; info->period = g_list_append(info->period, r); } info->period_menu = GNC_FREQUENCY( gnc_frequency_new_from_recurrence(info->period, &info->closing_date)); /* Change the text so that its more mainingful for this druid */ gnc_frequency_set_frequency_label_text(info->period_menu, _("Period:")); gnc_frequency_set_date_label_text(info->period_menu, _("Closing Date:")); /* Reparent to the correct location */ w = glade_xml_get_widget (xml, "period box"); gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (info->period_menu), TRUE, TRUE, 0); /* Get handles to all of the other widgets we'll need */ info->period_remarks = GTK_LABEL (glade_xml_get_widget (xml, "remarks label")); info->close_results = GTK_LABEL (glade_xml_get_widget (xml, "results label")); info->book_details = GTK_LABEL (glade_xml_get_widget (xml, "book label")); info->book_title = GTK_ENTRY (glade_xml_get_widget (xml, "book title entry")); info->book_notes = GTK_TEXT_VIEW (glade_xml_get_widget (xml, "book notes text")); /* generic finished/close/abort signals */ g_signal_connect (info->window, "destroy", G_CALLBACK (ap_window_destroy_cb), info); g_signal_connect (info->druid, "cancel", G_CALLBACK (ap_druid_cancel), info); g_signal_connect (info->menu_page, "prepare", G_CALLBACK (ap_show_menu), info); g_signal_connect (info->menu_page, "next", G_CALLBACK (ap_validate_menu), info); g_signal_connect (info->book_page, "prepare", G_CALLBACK (ap_show_book), info); g_signal_connect (info->book_page, "next", G_CALLBACK (ap_close_period), info); g_signal_connect (info->finish_page, "prepare", G_CALLBACK (ap_show_done), info); g_signal_connect (info->finish_page, "finish", G_CALLBACK (ap_finish), info); /* User changes the accouting period or date signals */ g_signal_connect (info->period_menu, "changed", G_CALLBACK (ap_changed), info); }
const Recurrence * gnc_recurrence_get(GncRecurrence *gr) { guint mult; UIPeriodType period; PeriodType pt; GDate start; gboolean use_eom = FALSE, rel; mult = (guint) gtk_spin_button_get_value_as_int(gr->gsb_mult); gnc_date_edit_get_gdate(GNC_DATE_EDIT(gr->gde_start), &start); period = get_pt_ui(gr); switch (period) { case GNCR_DAY: pt = PERIOD_DAY; break; case GNCR_WEEK: pt = PERIOD_WEEK; break; case GNCR_MONTH: rel = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(gr->nth_weekday)); if (rel) { if (is_ambiguous_relative(&start)) { use_eom = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(gr->gcb_eom)); } else { GDateDay d; d = g_date_get_day(&start); use_eom = ((d - 1) / 7 == 4); } if (use_eom) pt = PERIOD_LAST_WEEKDAY; else pt = PERIOD_NTH_WEEKDAY; } else { if (g_date_is_last_of_month(&start) && (g_date_get_day(&start) < 31)) { // ambiguous, need to examine the checkbox use_eom = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(gr->gcb_eom)); } else { // if it's the last dom, use eom anyway because it's the 31st. use_eom = g_date_is_last_of_month(&start); } if (use_eom) pt = PERIOD_END_OF_MONTH; else pt = PERIOD_MONTH; } break; case GNCR_YEAR: pt = PERIOD_YEAR; break; default: pt = PERIOD_INVALID; } recurrenceSet(&gr->recurrence, mult, pt, &start, WEEKEND_ADJ_NONE); return &gr->recurrence; }