r15630 - gnucash/trunk/src - 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.

Josh Sled jsled at cvs.gnucash.org
Mon Feb 19 16:16:52 EST 2007


Author: jsled
Date: 2007-02-19 16:16:51 -0500 (Mon, 19 Feb 2007)
New Revision: 15630
Trac: http://svn.gnucash.org/trac/changeset/15630

Modified:
   gnucash/trunk/src/doc/sx.rst
   gnucash/trunk/src/engine/Recurrence.c
   gnucash/trunk/src/engine/Recurrence.h
   gnucash/trunk/src/gnome-utils/gnc-frequency.c
   gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.c
Log:
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.


Modified: gnucash/trunk/src/doc/sx.rst
===================================================================
--- gnucash/trunk/src/doc/sx.rst	2007-02-19 19:47:03 UTC (rev 15629)
+++ gnucash/trunk/src/doc/sx.rst	2007-02-19 21:16:51 UTC (rev 15630)
@@ -137,8 +137,9 @@
     - [ ] 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

Modified: gnucash/trunk/src/engine/Recurrence.c
===================================================================
--- gnucash/trunk/src/engine/Recurrence.c	2007-02-19 19:47:03 UTC (rev 15629)
+++ gnucash/trunk/src/engine/Recurrence.c	2007-02-19 21:16:51 UTC (rev 15630)
@@ -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 @@
 
     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 @@
             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);
+}
+

Modified: gnucash/trunk/src/engine/Recurrence.h
===================================================================
--- gnucash/trunk/src/engine/Recurrence.h	2007-02-19 19:47:03 UTC (rev 15629)
+++ gnucash/trunk/src/engine/Recurrence.h	2007-02-19 21:16:51 UTC (rev 15630)
@@ -128,12 +128,14 @@
    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 @@
 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 */

Modified: gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.c	2007-02-19 19:47:03 UTC (rev 15629)
+++ gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.c	2007-02-19 21:16:51 UTC (rev 15630)
@@ -494,7 +494,7 @@
         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);

Modified: gnucash/trunk/src/gnome-utils/gnc-frequency.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-frequency.c	2007-02-19 19:47:03 UTC (rev 15629)
+++ gnucash/trunk/src/gnome-utils/gnc-frequency.c	2007-02-19 21:16:51 UTC (rev 15630)
@@ -896,51 +896,6 @@
     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 @@
 
      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 @@
                  _setup_weekly_recurrence(gf, (Recurrence*)recurrences->data);
              }
          }
-         else if (_test_for_semi_monthly(recurrences))
+         else if (recurrenceListIsSemiMonthly(recurrences))
          {
              Recurrence *first, *second;
              GtkWidget *multiplier_spin;



More information about the gnucash-changes mailing list