Add a "compact" toString of a Recurrence list; this is a clone of the FreqSpec method that is used by the SX List as a summary of the period of the SX.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@15630 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled 2007-02-19 21:16:51 +00:00
parent 20675026fc
commit c123a68e28
5 changed files with 267 additions and 56 deletions

View File

@ -137,8 +137,9 @@ TODO
- [ ] gnc_sxed_check_consistent
- [x] gnc_sxed_update_cal
- [x] gnc_sxed_save_sx
- gnc-instances
- [ ] More compact recurrenceListToString(...).
- sx list
- [ ] recurrence_cmp(...)
- [x] More compact recurrenceListToString(...).
- [ ] remove FreqSpec code
- [ ] SX code
- [ ] src/gnome/druid-acct-period.c

View File

@ -21,6 +21,7 @@
#include "config.h"
#include <time.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "glib-compat.h"
#include <string.h>
#include "Recurrence.h"
@ -30,7 +31,10 @@
#include "gnc-gdate-utils.h"
#include "Account.h"
static QofLogModule log_module = GNC_MOD_ENGINE;
#define LOG_MOD "gnc.engine.recurrence"
static QofLogModule log_module = LOG_MOD;
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN LOG_MOD
static GDate invalid_gdate;
@ -318,12 +322,12 @@ recurrenceListToString(const GList *r)
str = g_string_new("");
for(iter = r; iter; iter = iter->next){
if (iter != r)
g_string_append(str, " + ");
s = recurrenceToString((Recurrence *)iter->data);
g_string_append(str, s);
g_string_append(str, " + ");
g_free(s);
}
g_string_truncate(str, str->len - 3); /* kill the last " + " */
return g_string_free(str, FALSE);
}
@ -343,3 +347,233 @@ recurrencePeriodTypeFromString(const gchar *str)
return i;
return -1;
}
gboolean
recurrenceListIsSemiMonthly(GList *recurrences)
{
if (g_list_length(recurrences) != 2)
return FALSE;
// should be a "semi-monthly":
{
Recurrence *first = (Recurrence*)g_list_nth_data(recurrences, 0);
Recurrence *second = (Recurrence*)g_list_nth_data(recurrences, 1);
PeriodType first_period, second_period;
first_period = recurrenceGetPeriodType(first);
second_period = recurrenceGetPeriodType(second);
if (!((first_period == PERIOD_MONTH
|| first_period == PERIOD_END_OF_MONTH
|| first_period == PERIOD_LAST_WEEKDAY)
&& (second_period == PERIOD_MONTH
|| second_period == PERIOD_END_OF_MONTH
|| second_period == PERIOD_LAST_WEEKDAY)))
{
/*g_error("unknown 2-recurrence composite with period_types first [%d] second [%d]",
first_period, second_periodD);*/
return FALSE;
}
}
return TRUE;
}
gboolean
recurrenceListIsWeeklyMultiple(GList *recurrences)
{
GList *r_iter;
for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next)
{
Recurrence *r = (Recurrence*)r_iter->data;
if (recurrenceGetPeriodType(r) != PERIOD_WEEK)
{
return FALSE;
}
}
return TRUE;
}
/**
* Localized DOW abbrev.
* @fixme - ripped from gnc-dense-cal.c; there can be only one. :p
* @param dow struct tm semantics: 0=sunday .. 6=saturday
**/
static void
_dow_abbrev(gchar *buf, int buf_len, int dow)
{
struct tm my_tm;
int i;
memset(buf, 0, buf_len);
memset(&my_tm, 0, sizeof(struct tm));
my_tm.tm_wday = dow;
i = strftime(buf, buf_len - 1, "%a", &my_tm);
buf[i] = 0;
}
static void
_weekly_list_to_compact_string(GList *rs, GString *buf)
{
int dow_idx;
char dow_present_bits = 0;
int multiplier = -1;
for (; rs != NULL; rs = rs->next)
{
Recurrence *r = (Recurrence*)rs->data;
GDate date = recurrenceGetDate(r);
GDateWeekday dow = g_date_get_weekday(&date);
if (dow == G_DATE_BAD_WEEKDAY)
{
g_critical("bad weekday pretty-printing recurrence");
continue;
}
dow_present_bits |= (1 << (dow % 7));
// broken, @fixme.
multiplier = recurrenceGetMultiplier(r);
}
g_string_printf(buf, _("Weekly"));
if (multiplier > 1)
{
/* translators: %u is the recurrence multipler. */
g_string_append_printf(buf, _(" (x%u)"), multiplier);
}
g_string_append_printf(buf, ": ");
// @@fixme: this is only Sunday-started weeks. :/
for (dow_idx = 0; dow_idx < 7; dow_idx++)
{
if ((dow_present_bits & (1 << dow_idx)) != 0)
{
gchar dbuf[10];
_dow_abbrev(dbuf, 10, dow_idx);
g_string_append_printf(buf, "%c", dbuf[0]);
}
else
{
g_string_append_printf(buf, "-");
}
}
}
static void
_monthly_append_when(Recurrence *r, GString *buf)
{
GDate date = recurrenceGetDate(r);
if (recurrenceGetPeriodType(r) == PERIOD_LAST_WEEKDAY)
{
gint abbrev_day_name_bufsize = 10;
gchar day_name_buf[abbrev_day_name_bufsize];
_dow_abbrev(day_name_buf, abbrev_day_name_bufsize, g_date_get_weekday(&date) % 7);
/* translators: %s is an already-localized form of the day of the week. */
g_string_append_printf(buf, _("last %s"), day_name_buf);
}
else
{
/* translators: %u is the day of month */
g_string_append_printf(buf, "%u", g_date_get_day(&date));
}
}
gchar*
recurrenceListToCompactString(GList *rs)
{
GString *buf = g_string_sized_new(16);
if (g_list_length(rs) == 0)
{
g_string_printf(buf, _("None"));
goto rtn;
}
if (g_list_length(rs) > 1)
{
if (recurrenceListIsWeeklyMultiple(rs))
{
_weekly_list_to_compact_string(rs, buf);
}
else if (recurrenceListIsSemiMonthly(rs))
{
Recurrence *first, *second;
first = (Recurrence*)g_list_nth_data(rs, 0);
second = (Recurrence*)g_list_nth_data(rs, 1);
if (recurrenceGetMultiplier(first) != recurrenceGetMultiplier(second))
{
g_warning("lying about non-equal semi-monthly recurrence multiplier: %d vs. %d",
recurrenceGetMultiplier(first), recurrenceGetMultiplier(second));
}
g_string_printf(buf, _("Semi-monthly "));
if (recurrenceGetMultiplier(first) > 1)
{
/* translators: %u is the recurrence multiplier */
g_string_append_printf(buf, _(" (x%u)"), recurrenceGetMultiplier(first));
}
g_string_append_printf(buf, _(": "));
_monthly_append_when(first, buf);
g_string_append_printf(buf, ", ");
_monthly_append_when(second, buf);
}
else
{
/* translators: %d is the number of Recurrences in the list. */
g_string_printf(buf, _("Unknown, %d-size list."), g_list_length(rs));
}
}
else
{
Recurrence *r = (Recurrence*)g_list_nth_data(rs, 0);
guint multiplier = recurrenceGetMultiplier(r);
GDate date = recurrenceGetDate(r);
switch (recurrenceGetPeriodType(r))
{
case PERIOD_ONCE: {
g_string_printf(buf, _("Once"));
} break;
case PERIOD_DAY: {
g_string_printf(buf, _("Daily"));
if (multiplier > 1)
{
/* translators: %u is the number of intervals */
g_string_append_printf(buf, _(" (x%u)"), multiplier);
}
} break;
case PERIOD_WEEK: {
_weekly_list_to_compact_string(rs, buf);
} break;
case PERIOD_MONTH:
case PERIOD_END_OF_MONTH:
case PERIOD_LAST_WEEKDAY: {
g_string_printf(buf, _("Monthly"));
if (multiplier > 1)
{
/* translators: %u is the recurrence multipler. */
g_string_append_printf(buf, _(" (x%u)"), multiplier);
}
g_string_append_printf(buf, _(": "));
_monthly_append_when(r, buf);
} break;
case PERIOD_NTH_WEEKDAY: {
g_warning("nth weekday unhandled");
g_string_printf(buf, "@fixme: nth weekday");
} break;
case PERIOD_YEAR: {
g_string_printf(buf, _("Yearly"));
if (multiplier > 1)
{
/* translators: %u is the recurrence multiplier. */
g_string_append_printf(buf, _(" (x%u)"), multiplier);
}
} break;
default:
g_error("unknown Recurrnce period %d", recurrenceGetPeriodType(r));
break;
}
}
rtn:
return g_string_free(buf, FALSE);
}

View File

@ -128,12 +128,14 @@ void recurrenceNthInstance(const Recurrence *r, guint n, GDate *date);
of the nth instance of the recurrence. Also zero-based. */
time_t recurrenceGetPeriodTime(const Recurrence *r, guint n, gboolean end);
/* Get the amount that an Account's value changed between the
beginning and end of the nth instance of the recurrence. */
/**
* @return the amount that an Account's value changed between the beginning
* and end of the nth instance of the Recurrence.
**/
gnc_numeric recurrenceGetAccountPeriodValue(const Recurrence *r,
Account *acct, guint n);
/* Get the earliest of the next occurances -- a "composite" recurrence */
/** @return the earliest of the next occurances -- a "composite" recurrence **/
void recurrenceListNextInstance(const GList *r, const GDate *refDate,
GDate *nextDate);
@ -145,4 +147,23 @@ PeriodType recurrencePeriodTypeFromString(const gchar *str);
gchar *recurrenceToString(const Recurrence *r);
gchar *recurrenceListToString(const GList *rlist);
/** @return True if the recurrence list is a common "semi-monthly" recurrence. **/
gboolean recurrenceListIsSemiMonthly(GList *recurrences);
/** @return True if the recurrence list is a common "weekly" recurrence. **/
gboolean recurrenceListIsWeeklyMultiple(GList *recurrences);
/**
* Pretty-print an intentionally-short summary of the period of a (GList of)
* Recurrences, as might be commonly-created by the GncFrequency widget. In
* particular, this routine expects most lists to contain a single
* Recurrence, but also anticipates 2 "composite" scenarios:
*
* @li A list of N PERIOD_WEEK Recurrences.
* @li A list of 2 PERIOD_MONTH or PERIOD_LAST_WEEKDAY Recurrences,
* representing a Semi-Monthly period.
*
* @return A caller-owned string.
**/
gchar *recurrenceListToCompactString(GList *recurrence_list);
#endif /* RECURRENCE_H */

View File

@ -896,51 +896,6 @@ gnc_frequency_new_from_recurrence(GList *recurrences, GDate *start_date)
return GTK_WIDGET(toRet);
}
static gboolean
_test_for_semi_monthly(GList *recurrences)
{
if (g_list_length(recurrences) != 2)
return FALSE;
// should be a "semi-monthly":
{
Recurrence *first = (Recurrence*)g_list_nth_data(recurrences, 0);
Recurrence *second = (Recurrence*)g_list_nth_data(recurrences, 1);
PeriodType first_period, second_period;
first_period = recurrenceGetPeriodType(first);
second_period = recurrenceGetPeriodType(second);
if (!((first_period == PERIOD_MONTH
|| first_period == PERIOD_END_OF_MONTH
|| first_period == PERIOD_LAST_WEEKDAY)
&& (second_period == PERIOD_MONTH
|| second_period == PERIOD_END_OF_MONTH
|| second_period == PERIOD_LAST_WEEKDAY)))
{
/*g_error("unknown 2-recurrence composite with period_types first [%d] second [%d]",
first_period, second_periodD);*/
return FALSE;
}
}
return TRUE;
}
static gboolean
_test_for_weekly_multiple(GList *recurrences)
{
GList *r_iter;
for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next)
{
Recurrence *r = (Recurrence*)r_iter->data;
if (recurrenceGetPeriodType(r) != PERIOD_WEEK)
{
return FALSE;
}
}
return TRUE;
}
static void
_setup_weekly_recurrence(GncFrequency *gf, Recurrence *r)
{
@ -999,7 +954,7 @@ gnc_frequency_setup_recurrence(GncFrequency *gf, GList *recurrences, GDate *star
if (g_list_length(recurrences) > 1)
{
if (_test_for_weekly_multiple(recurrences))
if (recurrenceListIsWeeklyMultiple(recurrences))
{
gtk_notebook_set_current_page(gf->nb, PAGE_WEEKLY);
gtk_combo_box_set_active(gf->freqComboBox, PAGE_WEEKLY);
@ -1009,7 +964,7 @@ gnc_frequency_setup_recurrence(GncFrequency *gf, GList *recurrences, GDate *star
_setup_weekly_recurrence(gf, (Recurrence*)recurrences->data);
}
}
else if (_test_for_semi_monthly(recurrences))
else if (recurrenceListIsSemiMonthly(recurrences))
{
Recurrence *first, *second;
GtkWidget *multiplier_spin;

View File

@ -494,7 +494,7 @@ gsltma_populate_tree_store(GncSxListTreeModelAdapter *model)
char last_occur_date_buf[MAX_DATE_LENGTH+1];
char next_occur_date_buf[MAX_DATE_LENGTH+1];
frequency_str = recurrenceListToString(gnc_sx_get_schedule(instances->sx));
frequency_str = recurrenceListToCompactString(gnc_sx_get_schedule(instances->sx));
_format_conditional_date(xaccSchedXactionGetLastOccurDate(instances->sx),
last_occur_date_buf, MAX_DATE_LENGTH);