GDate xaccSchedXactionGetNextInstance (const SchedXaction *sx, SXTmpStateData *tsd) { GDate prev_occur, next_occur; g_date_clear( &prev_occur, 1 ); if ( tsd != NULL ) prev_occur = tsd->last_date; /* If prev_occur is in the "cleared" state and sx->start_date isn't, then * we're at the beginning. We want to pretend prev_occur is the day before * the start_date in case the start_date is today so that the SX will fire * today. If start_date isn't valid either then the SX will fire anyway, no * harm done. */ if (! g_date_valid( &prev_occur ) && g_date_valid(&sx->start_date)) { /* We must be at the beginning. */ prev_occur = sx->start_date; g_date_subtract_days( &prev_occur, 1 ); } recurrenceListNextInstance(sx->schedule, &prev_occur, &next_occur); if ( xaccSchedXactionHasEndDate( sx ) ) { const GDate *end_date = xaccSchedXactionGetEndDate( sx ); if ( g_date_compare( &next_occur, end_date ) > 0 ) { g_date_clear( &next_occur, 1 ); } } else if ( xaccSchedXactionHasOccurDef( sx ) ) { if ((tsd && tsd->num_occur_rem == 0) || (!tsd && sx->num_occurances_remain == 0 )) { g_date_clear( &next_occur, 1 ); } } return next_occur; }
gint gnc_sx_get_num_occur_daterange(const SchedXaction *sx, const GDate* start_date, const GDate* end_date) { gint result = 0; SXTmpStateData *tmpState; gboolean countFirstDate; /* SX still active? If not, return now. */ if ((xaccSchedXactionHasOccurDef(sx) && xaccSchedXactionGetRemOccur(sx) <= 0) || (xaccSchedXactionHasEndDate(sx) && g_date_compare(xaccSchedXactionGetEndDate(sx), start_date) < 0)) { return result; } tmpState = gnc_sx_create_temporal_state (sx); /* Should we count the first valid date we encounter? Only if the * SX has not yet occurred so far, or if its last valid date was * before the start date. */ countFirstDate = !g_date_valid(&tmpState->last_date) || (g_date_compare(&tmpState->last_date, start_date) < 0); /* No valid date? SX has never occurred so far. */ if (!g_date_valid(&tmpState->last_date)) { /* SX has never occurred so far */ gnc_sx_incr_temporal_state (sx, tmpState); if (xaccSchedXactionHasOccurDef(sx) && tmpState->num_occur_rem < 0) { gnc_sx_destroy_temporal_state (tmpState); return result; } } /* Increase the tmpState until we are in our interval of * interest. Only calculate anything if the sx hasn't already * ended. */ while (g_date_compare(&tmpState->last_date, start_date) < 0) { gnc_sx_incr_temporal_state (sx, tmpState); if (xaccSchedXactionHasOccurDef(sx) && tmpState->num_occur_rem < 0) { gnc_sx_destroy_temporal_state (tmpState); return result; } } /* Now we are in our interval of interest. Increment the * occurrence date until we are beyond the end of our * interval. Make sure to check for invalid dates here: It means * the SX has ended. */ while (g_date_valid(&tmpState->last_date) && (g_date_compare(&tmpState->last_date, end_date) <= 0) && (!xaccSchedXactionHasEndDate(sx) || g_date_compare(&tmpState->last_date, xaccSchedXactionGetEndDate(sx)) <= 0) && (!xaccSchedXactionHasOccurDef(sx) /* The >=0 (i.e. the ==) is important here, otherwise * we miss the last valid occurrence of a SX which is * limited by num_occur */ || tmpState->num_occur_rem >= 0)) { ++result; gnc_sx_incr_temporal_state (sx, tmpState); } /* If the first valid date shouldn't be counted, decrease the * result number by one. */ if (!countFirstDate && result > 0) --result; gnc_sx_destroy_temporal_state (tmpState); return result; }
xmlNodePtr gnc_schedXaction_dom_tree_create(SchedXaction *sx) { xmlNodePtr ret; const GDate *date; gint instCount; const GncGUID *templ_acc_guid; gboolean allow_2_2_incompat = TRUE; gchar *name = g_strdup (xaccSchedXactionGetName(sx)); templ_acc_guid = xaccAccountGetGUID(sx->template_acct); /* FIXME: this should be the same as the def in io-gncxml-v2.c */ ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG); if (allow_2_2_incompat) xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string); else xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version_string); xmlAddChild( ret, guid_to_dom_tree(SX_ID, xaccSchedXactionGetGUID(sx)) ); xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name)); g_free (name); if (allow_2_2_incompat) { xmlNewTextChild( ret, NULL, BAD_CAST SX_ENABLED, BAD_CAST ( sx->enabled ? "y" : "n" ) ); } xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE, BAD_CAST ( sx->autoCreateOption ? "y" : "n" ) ); xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY, BAD_CAST ( sx->autoCreateNotify ? "y" : "n" ) ); xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_CREATE_DAYS, sx->advanceCreateDays)); xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS, sx->advanceRemindDays)); instCount = gnc_sx_get_instance_count( sx, NULL ); xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT, instCount ) ); xmlAddChild( ret, gdate_to_dom_tree( SX_START, xaccSchedXactionGetStartDate(sx) ) ); date = xaccSchedXactionGetLastOccurDate(sx); if ( g_date_valid( date ) ) { xmlAddChild( ret, gdate_to_dom_tree( SX_LAST, date ) ); } if ( xaccSchedXactionHasOccurDef(sx) ) { xmlAddChild(ret, int_to_dom_tree( SX_NUM_OCCUR, xaccSchedXactionGetNumOccur(sx))); xmlAddChild(ret, int_to_dom_tree( SX_REM_OCCUR, xaccSchedXactionGetRemOccur(sx))); } else if ( xaccSchedXactionHasEndDate(sx) ) { xmlAddChild( ret, gdate_to_dom_tree( SX_END, xaccSchedXactionGetEndDate(sx) ) ); } /* output template account GncGUID */ xmlAddChild( ret, guid_to_dom_tree(SX_TEMPL_ACCT, templ_acc_guid)); if (allow_2_2_incompat) { xmlNodePtr schedule_node = xmlNewNode(NULL, BAD_CAST "sx:schedule"); GList *schedule = gnc_sx_get_schedule(sx); for (; schedule != NULL; schedule = schedule->next) { xmlAddChild(schedule_node, recurrence_to_dom_tree("gnc:recurrence", (Recurrence*)schedule->data)); } xmlAddChild(ret, schedule_node); } /* Output deferred-instance list. */ { xmlNodePtr instNode; SXTmpStateData *tsd; GList *l; for ( l = gnc_sx_get_defer_instances( sx ); l; l = l->next ) { tsd = (SXTmpStateData*)l->data; instNode = xmlNewNode( NULL, BAD_CAST SX_DEFER_INSTANCE ); if ( g_date_valid( &tsd->last_date ) ) { xmlAddChild( instNode, gdate_to_dom_tree( SX_LAST, &tsd->last_date ) ); } xmlAddChild( instNode, int_to_dom_tree( SX_REM_OCCUR, tsd->num_occur_rem ) ); xmlAddChild( instNode, int_to_dom_tree( SX_INSTANCE_COUNT, tsd->num_inst ) ); xmlAddChild( ret, instNode ); } } /* output kvp_frame */ { xmlNodePtr kvpnode = kvp_frame_to_dom_tree( SX_SLOTS, xaccSchedXactionGetSlots(sx) ); if ( kvpnode ) { xmlAddChild(ret, kvpnode); } } return ret; }