r16594 - gnucash/branches/gda-dev/src - 1) Split out recurrence into its own table
Phil Longstaff
plongstaff at cvs.gnucash.org
Sun Nov 11 16:54:44 EST 2007
Author: plongstaff
Date: 2007-11-11 16:54:43 -0500 (Sun, 11 Nov 2007)
New Revision: 16594
Trac: http://svn.gnucash.org/trac/changeset/16594
Added:
gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.c
gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.h
Removed:
gnucash/branches/gda-dev/src/engine/FreqSpec.c
gnucash/branches/gda-dev/src/engine/FreqSpecP.h
Modified:
gnucash/branches/gda-dev/src/backend/gda/Makefile.am
gnucash/branches/gda-dev/src/backend/gda/gnc-backend-gda.c
gnucash/branches/gda-dev/src/backend/gda/gnc-backend-util-gda.c
gnucash/branches/gda-dev/src/backend/gda/gnc-budget-gda.c
Log:
1) Split out recurrence into its own table
2) Load/save recurrence as part of budget
3) Remove obsolete FreqSpec files
Modified: gnucash/branches/gda-dev/src/backend/gda/Makefile.am
===================================================================
--- gnucash/branches/gda-dev/src/backend/gda/Makefile.am 2007-11-11 17:32:56 UTC (rev 16593)
+++ gnucash/branches/gda-dev/src/backend/gda/Makefile.am 2007-11-11 21:54:43 UTC (rev 16594)
@@ -26,6 +26,7 @@
gnc-commodity-gda.c \
gnc-lots-gda.c \
gnc-price-gda.c \
+ gnc-recurrence-gda.c \
gnc-schedxaction-gda.c \
gnc-slots-gda.c \
gnc-transaction-gda.c
@@ -42,6 +43,7 @@
gnc-commodity-gda.h \
gnc-lots-gda.h \
gnc-price-gda.h \
+ gnc-recurrence-gda.h \
gnc-schedxaction-gda.h \
gnc-slots-gda.h \
gnc-transaction-gda.h
Modified: gnucash/branches/gda-dev/src/backend/gda/gnc-backend-gda.c
===================================================================
--- gnucash/branches/gda-dev/src/backend/gda/gnc-backend-gda.c 2007-11-11 17:32:56 UTC (rev 16593)
+++ gnucash/branches/gda-dev/src/backend/gda/gnc-backend-gda.c 2007-11-11 21:54:43 UTC (rev 16594)
@@ -40,6 +40,7 @@
#include "TransLog.h"
#include "gnc-engine.h"
#include "SX-book.h"
+#include "Recurrence.h"
#include "gnc-backend-util-gda.h"
#include "gnc-gconf-utils.h"
@@ -51,6 +52,7 @@
#include "gnc-lots-gda.h"
#include "gnc-price-gda.h"
#include "gnc-pricedb.h"
+#include "gnc-recurrence-gda.h"
#include "gnc-schedxaction-gda.h"
#include "gnc-slots-gda.h"
#include "gnc-transaction-gda.h"
@@ -925,6 +927,7 @@
gnc_gda_init_price_handler();
gnc_gda_init_transaction_handler();
gnc_gda_init_slots_handler();
+ gnc_gda_init_recurrence_handler();
gnc_gda_init_schedxaction_handler();
gnc_gda_init_lot_handler();
}
Modified: gnucash/branches/gda-dev/src/backend/gda/gnc-backend-util-gda.c
===================================================================
--- gnucash/branches/gda-dev/src/backend/gda/gnc-backend-util-gda.c 2007-11-11 17:32:56 UTC (rev 16593)
+++ gnucash/branches/gda-dev/src/backend/gda/gnc-backend-util-gda.c 2007-11-11 21:54:43 UTC (rev 16594)
@@ -532,7 +532,6 @@
g_free( buf );
} else if( G_VALUE_HOLDS_BOXED( val ) ) {
- const gchar* n = g_type_name( val->g_type );
date = (GDate*)g_value_get_boxed( val );
if( date != NULL ) {
ts = gnc_dmy2timespec( g_date_get_day( date ),
@@ -619,9 +618,22 @@
if( gda_value_is_null( val ) ) {
(*setter)( pObject, NULL );
} else {
- date = (GDate*)g_value_get_boxed( val );
- if( date != NULL ) {
- (*setter)( pObject, date );
+ if( G_VALUE_HOLDS_STRING( val ) ) {
+ const gchar* s = g_value_get_string( val );
+ guint year = atoi( &s[6] );
+ guint month = atoi( &s[0] );
+ guint day = atoi( &s[3] );
+
+ date = g_date_new_dmy( day, month, year );
+ (*setter)( pObject, date );
+
+ } else if( G_VALUE_HOLDS_BOXED( val ) ) {
+ date = (GDate*)g_value_get_boxed( val );
+ if( date != NULL ) {
+ (*setter)( pObject, date );
+ }
+ } else {
+ g_warning( "Unknown timespec type: %s", G_VALUE_TYPE_NAME( val ) );
}
}
}
Modified: gnucash/branches/gda-dev/src/backend/gda/gnc-budget-gda.c
===================================================================
--- gnucash/branches/gda-dev/src/backend/gda/gnc-budget-gda.c 2007-11-11 17:32:56 UTC (rev 16593)
+++ gnucash/branches/gda-dev/src/backend/gda/gnc-budget-gda.c 2007-11-11 21:54:43 UTC (rev 16594)
@@ -35,26 +35,20 @@
#include "gnc-backend-util-gda.h"
+#include "Recurrence.h"
+
#include "gnc-budget-gda.h"
#include "gnc-slots-gda.h"
+#include "gnc-recurrence-gda.h"
#include "gnc-budget.h"
-#include "Recurrence.h"
#define BUDGET_TABLE "budgets"
static QofLogModule log_module = GNC_MOD_BACKEND;
-static gpointer get_recurrence_mult( gpointer pObject, const QofParam* );
-static void set_recurrence_mult( gpointer pObject, gpointer pValue );
-static gpointer get_recurrence_period_type( gpointer pObject, const QofParam* );
-static void set_recurrence_period_type( gpointer pObject, gpointer pValue );
-static gpointer get_recurrence_period_start( gpointer pObject, const QofParam* );
-static void set_recurrence_period_start( gpointer pObject, gpointer pValue );
-
#define BUDGET_MAX_NAME_LEN 50
#define BUDGET_MAX_DESCRIPTION_LEN 500
-#define BUDGET_MAX_RECURRENCE_PERIOD_TYPE_LEN 50
static col_cvt_t col_table[] =
{
@@ -64,83 +58,17 @@
{ "name", CT_STRING, BUDGET_MAX_NAME_LEN, COL_NNUL, NULL, "name" },
{ "description", CT_STRING, BUDGET_MAX_DESCRIPTION_LEN, 0, NULL, "description" },
{ "num_periods", CT_INT, 0, COL_NNUL, NULL, "num_periods" },
- { "recurrence_mult", CT_INT, 0, COL_NNUL, NULL, NULL,
- get_recurrence_mult, set_recurrence_mult },
- { "recurrence_period_type", CT_STRING, BUDGET_MAX_RECURRENCE_PERIOD_TYPE_LEN,
- COL_NNUL, NULL, NULL, get_recurrence_period_type, set_recurrence_period_type },
- { "recurrence_period_start", CT_GDATE, 0, COL_NNUL, NULL, NULL,
- get_recurrence_period_start, set_recurrence_period_start },
{ NULL }
};
/* ================================================================= */
-static gpointer
-get_recurrence_mult( gpointer pObject, const QofParam* param )
-{
- GncBudget* budget = GNC_BUDGET(pObject);
- const Recurrence* r = gnc_budget_get_recurrence( budget );
- guint m = r->mult;
-
- return (gpointer)m;
-}
-
-static void
-set_recurrence_mult( gpointer pObject, gpointer pValue )
-{
- GncBudget* budget = GNC_BUDGET(pObject);
- Recurrence* r = (Recurrence*)gnc_budget_get_recurrence( budget );
- guint m = (guint)pValue;
-
- r->mult = m;
-}
-
-static gpointer
-get_recurrence_period_type( gpointer pObject, const QofParam* param )
-{
- GncBudget* budget = GNC_BUDGET(pObject);
- const Recurrence* r = gnc_budget_get_recurrence( budget );
-
- return (gpointer)recurrencePeriodTypeToString(
- recurrenceGetPeriodType( r ) );
-}
-
-static void
-set_recurrence_period_type( gpointer pObject, gpointer pValue )
-{
- GncBudget* budget = GNC_BUDGET(pObject);
- Recurrence* r = (Recurrence*)gnc_budget_get_recurrence( budget );
-
- r->ptype = recurrencePeriodTypeFromString( (gchar*)pValue );
-}
-
-static gpointer
-get_recurrence_period_start( gpointer pObject, const QofParam* param )
-{
- GncBudget* budget = GNC_BUDGET(pObject);
- const Recurrence* r = gnc_budget_get_recurrence( budget );
- static GDate date;
-
- date = recurrenceGetDate( r );
- return (gpointer)&date;
-}
-
-static void
-set_recurrence_period_start( gpointer pObject, gpointer pValue )
-{
- GncBudget* budget = GNC_BUDGET(pObject);
- Recurrence* r = (Recurrence*)gnc_budget_get_recurrence( budget );
- GDate* date = (GDate*)pValue;
-
- r->start = *date;
-}
-
-/* ================================================================= */
static GncBudget*
load_single_budget( GncGdaBackend* be, GdaDataModel* pModel, int row )
{
const GUID* guid;
GUID budget_guid;
GncBudget* pBudget;
+ Recurrence* r;
guid = gnc_gda_load_guid( pModel, row );
budget_guid = *guid;
@@ -151,6 +79,8 @@
}
gnc_gda_load_object( pModel, row, GNC_ID_BUDGET, pBudget, col_table );
+ r = g_new0( Recurrence, 1 );
+ gnc_gda_recurrence_load( be, gnc_budget_get_guid( pBudget ), r );
gnc_gda_slots_load( be, gnc_budget_get_guid( pBudget ),
qof_instance_get_slots( QOF_INSTANCE(pBudget) ) );
@@ -201,13 +131,13 @@
GNC_ID_BUDGET, pBudget,
col_table );
- // Delete old slot info
+ // Now, commit any slots and recurrence
guid = qof_instance_get_guid( inst );
-
- // Now, commit any slots
if( !qof_instance_get_destroying(inst) ) {
+ gnc_gda_recurrence_save( be, guid, gnc_budget_get_recurrence( pBudget ) );
gnc_gda_slots_save( be, guid, qof_instance_get_slots( inst ) );
} else {
+ gnc_gda_recurrence_delete( be, guid );
gnc_gda_slots_delete( be, guid );
}
}
Added: gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.c
===================================================================
--- gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.c (rev 0)
+++ gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.c 2007-11-11 21:54:43 UTC (rev 16594)
@@ -0,0 +1,300 @@
+/********************************************************************
+ * gnc-recurrence-gda.c: load and save data to SQL via libgda *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+\********************************************************************/
+/** @file gnc-recurrence-gda.c
+ * @brief load and save data to SQL
+ * @author Copyright (c) 2006, 2007 Phil Longstaff <plongstaff at rogers.com>
+ *
+ * This file implements the top-level QofBackend API for saving/
+ * restoring data to/from an SQL db using libgda
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <libgda/libgda.h>
+
+#include "qof.h"
+#include "gnc-engine.h"
+#include "Recurrence.h"
+
+#include "gnc-backend-util-gda.h"
+
+#include "gnc-recurrence-gda.h"
+
+static QofLogModule log_module = GNC_MOD_BACKEND;
+
+#define TABLE_NAME "recurrences"
+
+#define BUDGET_MAX_RECURRENCE_PERIOD_TYPE_LEN 50
+
+typedef struct {
+ GncGdaBackend* be;
+ const GUID* guid;
+ Recurrence* pRecurrence;
+} recurrence_info_t;
+
+static gpointer get_recurrence_id( gpointer pObject, const QofParam* param );
+static void set_recurrence_id( gpointer pObject, gpointer pValue );
+static gpointer get_obj_guid( gpointer pObject, const QofParam* param );
+static void set_obj_guid( gpointer pObject, gpointer pValue );
+static gpointer get_recurrence_mult( gpointer pObject, const QofParam* );
+static void set_recurrence_mult( gpointer pObject, gpointer pValue );
+static gpointer get_recurrence_period_type( gpointer pObject, const QofParam* );
+static void set_recurrence_period_type( gpointer pObject, gpointer pValue );
+static gpointer get_recurrence_period_start( gpointer pObject, const QofParam* );
+static void set_recurrence_period_start( gpointer pObject, gpointer pValue );
+
+static col_cvt_t col_table[] =
+{
+ { "recurrence_id", CT_INT, 0, COL_NNUL|COL_PKEY|COL_AUTOINC, NULL, NULL,
+ get_recurrence_id, set_recurrence_id },
+ { "obj_guid", CT_GUID, 0, COL_NNUL, NULL, NULL,
+ get_obj_guid, set_obj_guid },
+ { "recurrence_mult", CT_INT, 0, COL_NNUL, NULL, NULL,
+ get_recurrence_mult, set_recurrence_mult },
+ { "recurrence_period_type", CT_STRING, BUDGET_MAX_RECURRENCE_PERIOD_TYPE_LEN,
+ COL_NNUL, NULL, NULL, get_recurrence_period_type, set_recurrence_period_type },
+ { "recurrence_period_start", CT_GDATE, 0, COL_NNUL, NULL, NULL,
+ get_recurrence_period_start, set_recurrence_period_start },
+ { NULL }
+};
+
+/* Special column table because we need to be able to access the table by
+a column other than the primary key */
+static col_cvt_t guid_col_table[] =
+{
+ { "obj_guid", CT_GUID, 0, COL_NNUL, NULL, NULL,
+ get_obj_guid, set_obj_guid },
+ { NULL }
+};
+
+/* ================================================================= */
+
+static gpointer
+get_recurrence_id( gpointer pObject, const QofParam* param )
+{
+ // Just need a 0 to force a new recurrence id
+ return (gpointer)0;
+}
+
+static void
+set_recurrence_id( gpointer pObject, gpointer pValue )
+{
+ // Nowhere to put the ID
+}
+
+static gpointer
+get_obj_guid( gpointer pObject, const QofParam* param )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+
+ return (gpointer)pInfo->guid;
+}
+
+static void
+set_obj_guid( gpointer pObject, gpointer pValue )
+{
+ // Nowhere to put the GUID
+}
+
+static gpointer
+get_recurrence_mult( gpointer pObject, const QofParam* param )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+ static guint m;
+
+ m = pInfo->pRecurrence->mult;
+
+ return (gpointer)m;
+}
+
+static void
+set_recurrence_mult( gpointer pObject, gpointer pValue )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+ guint m = (guint)pValue;
+
+ pInfo->pRecurrence->mult = m;
+}
+
+static gpointer
+get_recurrence_period_type( gpointer pObject, const QofParam* param )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+
+ return (gpointer)recurrencePeriodTypeToString(
+ recurrenceGetPeriodType( pInfo->pRecurrence ) );
+}
+
+static void
+set_recurrence_period_type( gpointer pObject, gpointer pValue )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+
+ pInfo->pRecurrence->ptype = recurrencePeriodTypeFromString( (gchar*)pValue );
+}
+
+static gpointer
+get_recurrence_period_start( gpointer pObject, const QofParam* param )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+ static GDate date;
+
+ date = recurrenceGetDate( pInfo->pRecurrence );
+ return (gpointer)&date;
+}
+
+static void
+set_recurrence_period_start( gpointer pObject, gpointer pValue )
+{
+ recurrence_info_t* pInfo = (recurrence_info_t*)pObject;
+ GDate* date = (GDate*)pValue;
+
+ pInfo->pRecurrence->start = *date;
+}
+
+/* ================================================================= */
+
+void
+gnc_gda_recurrence_save( GncGdaBackend* be, const GUID* guid, const Recurrence* r )
+{
+ recurrence_info_t recurrence_info;
+
+ gnc_gda_recurrence_delete( be, guid );
+
+ recurrence_info.be = be;
+ recurrence_info.guid = guid;
+ recurrence_info.pRecurrence = (Recurrence*)r;
+ (void)gnc_gda_do_db_operation( be, OP_DB_ADD, TABLE_NAME,
+ TABLE_NAME, &recurrence_info, col_table );
+}
+
+void
+gnc_gda_recurrence_delete( GncGdaBackend* be, const GUID* guid )
+{
+ recurrence_info_t recurrence_info;
+
+ recurrence_info.be = be;
+ recurrence_info.guid = guid;
+ (void)gnc_gda_do_db_operation( be, OP_DB_DELETE, TABLE_NAME,
+ TABLE_NAME, &recurrence_info, guid_col_table );
+}
+
+static void
+load_recurrence( GncGdaBackend* be, GdaDataModel* pModel, gint row, Recurrence* r )
+{
+ recurrence_info_t recurrence_info;
+
+ recurrence_info.be = be;
+ recurrence_info.pRecurrence = r;
+
+ gnc_gda_load_object( pModel, row, TABLE_NAME, &recurrence_info, col_table );
+}
+
+void
+gnc_gda_recurrence_load( GncGdaBackend* be, const GUID* guid, Recurrence* pRecurrence )
+{
+ gchar* buf;
+ GdaObject* ret;
+ gchar guid_buf[GUID_ENCODING_LENGTH+1];
+ gchar* field_name;
+
+ static GdaQuery* query = NULL;
+ GdaQueryCondition* cond;
+ GdaQueryField* key_value;
+ GValue value;
+
+ guid_to_string_buff( guid, guid_buf );
+
+ /* First time, create the query */
+ if( query == NULL ) {
+ GdaQueryTarget* target;
+ GdaQueryField* key;
+
+ /* SELECT */
+ query = gnc_gda_create_select_query( be, TABLE_NAME );
+ target = gda_query_get_target_by_alias( query, TABLE_NAME );
+
+ /* WHERE */
+ cond = gda_query_condition_new( query, GDA_QUERY_CONDITION_LEAF_EQUAL );
+ gda_query_set_condition( query, cond );
+
+ field_name = g_strdup_printf( "%s.%s",
+ gda_query_target_get_alias( target ), "obj_guid" );
+ key = gda_query_field_field_new( query, field_name );
+ g_free( field_name );
+ gda_query_field_set_visible( key, TRUE );
+ gda_query_condition_leaf_set_operator( cond,
+ GDA_QUERY_CONDITION_OP_LEFT,
+ GDA_QUERY_FIELD(key) );
+ g_object_unref( G_OBJECT(key) );
+
+ key_value = gda_query_field_value_new( query, G_TYPE_STRING );
+ gda_query_field_set_visible( key_value, TRUE );
+ gda_query_condition_leaf_set_operator( cond, GDA_QUERY_CONDITION_OP_RIGHT,
+ GDA_QUERY_FIELD(key_value) );
+ g_object_unref( G_OBJECT(key_value) );
+ }
+
+ /* Fill in the guid value */
+ cond = gda_query_get_condition( query );
+ key_value = gda_query_condition_leaf_get_operator( cond,
+ GDA_QUERY_CONDITION_OP_RIGHT );
+ memset( &value, 0, sizeof( value ) );
+ g_value_init( &value, G_TYPE_STRING );
+ g_value_set_string( &value, guid_buf );
+ gda_query_field_value_set_value( GDA_QUERY_FIELD_VALUE(key_value), &value );
+
+ ret = gnc_gda_execute_query( be, query );
+ if( GDA_IS_DATA_MODEL( ret ) ) {
+ GdaDataModel* pModel = GDA_DATA_MODEL(ret);
+ int numRows = gda_data_model_get_n_rows( pModel );
+ int r;
+
+ for( r = 0; r < numRows; r++ ) {
+ load_recurrence( be, pModel, r, pRecurrence );
+ }
+ }
+}
+
+/* ================================================================= */
+static void
+create_recurrence_tables( GncGdaBackend* be )
+{
+ gnc_gda_create_table_if_needed( be, TABLE_NAME, col_table );
+}
+
+/* ================================================================= */
+void
+gnc_gda_init_recurrence_handler( void )
+{
+ static GncGdaDataType_t be_data =
+ {
+ GNC_GDA_BACKEND_VERSION,
+ GNC_ID_ACCOUNT,
+ NULL, /* commit - cannot occur */
+ NULL, /* initial_load - cannot occur */
+ create_recurrence_tables /* create_tables */
+ };
+
+ qof_object_register_backend( TABLE_NAME, GNC_GDA_BACKEND, &be_data );
+}
+/* ========================== END OF FILE ===================== */
Added: gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.h
===================================================================
--- gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.h (rev 0)
+++ gnucash/branches/gda-dev/src/backend/gda/gnc-recurrence-gda.h 2007-11-11 21:54:43 UTC (rev 16594)
@@ -0,0 +1,41 @@
+/********************************************************************
+ * gnc-recurrence-gda.h: load and save data to SQL via libgda *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+\********************************************************************/
+/** @file gnc-recurrence-gda.h
+ * @brief load and save accounts data to SQL via libgda
+ * @author Copyright (c) 2006-2007 Phil Longstaff <plongstaff at rogers.com>
+ *
+ * This file implements the top-level QofBackend API for saving/
+ * restoring data to/from an SQL database via libgda
+ */
+
+#ifndef GNC_RECURRENCE_GDA_H_
+#define GNC_RECURRENCE_GDA_H_
+
+#include "qof.h"
+#include <gmodule.h>
+
+void gnc_gda_recurrence_save( GncGdaBackend* be, const GUID* guid, const Recurrence* pRecurrence );
+void gnc_gda_recurrence_delete( GncGdaBackend* be, const GUID* guid );
+void gnc_gda_recurrence_load( GncGdaBackend* be, const GUID* guid, Recurrence* pRecurrence );
+
+void gnc_gda_init_recurrence_handler( void );
+
+#endif /* GNC_RECURRENCE_GDA_H_ */
Deleted: gnucash/branches/gda-dev/src/engine/FreqSpec.c
===================================================================
--- gnucash/branches/gda-dev/src/engine/FreqSpec.c 2007-11-11 17:32:56 UTC (rev 16593)
+++ gnucash/branches/gda-dev/src/engine/FreqSpec.c 2007-11-11 21:54:43 UTC (rev 16594)
@@ -1,1347 +0,0 @@
-/********************************************************************\
- * FreqSpec.c -- Frequency specifier implementation. *
- * Copyright (C) 2001 Joshua Sled <jsled at asynchronous.org> *
- * Copyright (C) 2001 Ben Stanley <bds02 at uow.edu.au> *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License as *
- * published by the Free Software Foundation; either version 2 of *
- * the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License*
- * along with this program; if not, contact: *
- * *
- * Free Software Foundation Voice: +1-617-542-5942 *
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
- * Boston, MA 02110-1301, USA gnu at gnu.org *
- * *
-\********************************************************************/
-
-/********************************************************************\
- Current status
- All kinds of repeats work, including composites. This is tested -
- although composites need some more test cases to be put into the test
- suite - ../test/test-freq-spec.c
- FreqSpec objects are currently 'set' to give them the information
- they need. Separate methods for modifying currently existing FreqSpec
- objects are not provided. In the case of composites, you may add FreqSpec
- objects to a composite, and you may access a list of the FreqSpec objects
- which form the composite. This interface allows you to do damage...
-
- TODO list
- Ben Stanley 2001-04-02
- * Write xaccFreqSpecGetFreqStr (I wonder how this will be
- internationalised... I suspect that this code will need to be
- re-written for each language, because the code will have to
- generate grammar... It's more than just translating strings.)
- However, the first priority is to write one that works for
- English.
- * Write a function to allow you to query whether a given
- date forms part of the recurrence.
- * Write a method to get the previous recurrence
- * provide XML Load/Save functionality for this object.
- * Figure out xaccFreqSpecIsValidDate - I suspect that this is the
- 'query whether a given date forms part of the recurrence'
- above.
- * FIGURE OUT WHAT'S GOING ON WITH xaccFreqSpecGetUIType AND
- xaccFreqSpecSetUIType.
- * Try to reduce the size of the data structure. There are quite a few
- 32 bit fields which could be stored in about 8 bits.
- * Add public methods to allow for recurrences with an interval
- of 1 to be set without reference to an initial 'date' - monthly
- things in particular. Try to reduce the dependence on an initial
- date for the input to set up the recurrence.
-
- Questions:
- Is it best that the public interface stay as GDate, or should it
- really be a timespec? I have no problem with converting GDates to
- timespecs for load/save if that makes life easier.
-
- However, I chose to use GDate internally because I have used a *lot*
- of the date calculating ability of GDate in the internal implementation.
- GDate has simplified this work enormously compared to using struct tm
- and time_t. The engine's timespec object doesn't appear to have the
- required functionality either, so I would need to write the required
- functions for timespec (perhaps by implementing in terms of GDate?).
-
- Hopefully it's not too painful to leave GDate in the public interface
- and change other code to use it.
-\********************************************************************/
-
-#include "config.h"
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include "glib-compat.h"
-#include <string.h>
-#include <time.h>
-
-#include "FreqSpecP.h"
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "gnc.engine.freqspec"
-
-#define GDATE_STRING_SIZE 25
-#define GDATE_STRING_BUF_SIZE (GDATE_STRING_SIZE + 1)
-
-#define WDAY_NAME_WIDTH 100
-#define WDAY_BUF_WIDTH (WDAY_NAME_WIDTH + 1)
-
-/** PROTOTYPES ******************************************************/
-
-FROM_STRING_FUNC(UIFreqType, ENUM_LIST_UI)
-AS_STRING_FUNC(UIFreqType, ENUM_LIST_UI)
-
-FROM_STRING_FUNC(FreqType, ENUM_LIST_TYPE)
-AS_STRING_FUNC(FreqType, ENUM_LIST_TYPE)
-
-static int int_cmp( int a, int b );
-
-/*
- * Destroys all sub-FreqSpecs in a composite FreqSpec.
- * Assertion error if it's not a COMPOSITE FreqSpec.
- */
-void xaccFreqSpecCompositesClear( FreqSpec *fs );
-
-void subSpecsListMapDelete( gpointer data, gpointer user_data );
-
-
-static const char *
-get_wday_name(guint day)
-{
- static gchar wday_name[WDAY_BUF_WIDTH];
- struct tm t;
- memset( &t, 0, sizeof( t ) );
- t.tm_wday = day;
- qof_strftime(wday_name, WDAY_NAME_WIDTH, "%A", &t);
- return wday_name;
-}
-
-#if 0
-static const char *
-get_full_month_name(guint month)
-{
- static gchar month_name[WDAY_BUF_WIDTH];
- struct tm t;
- t.tm_mon = month;
- qof_strftime(month_name, WDAY_NAME_WIDTH, "%B", &t);
- return month_name;
-}
-#endif
-
-static const char *
-get_abbrev_month_name(guint month)
-{
- static gchar month_name[WDAY_BUF_WIDTH];
- struct tm t;
- memset( &t, 0, sizeof( t ) );
- t.tm_mon = month;
- qof_strftime(month_name, WDAY_NAME_WIDTH, "%b", &t);
- return month_name;
-}
-
-/* GObject initialization */
-QOF_GOBJECT_IMPL(gnc_freqspec, FreqSpec, QOF_TYPE_INSTANCE);
-
-static void
-gnc_freqspec_init(FreqSpec* fs)
-{
-}
-
-static void
-gnc_freqspec_dispose_real (GObject *fsp)
-{
-}
-
-static void
-gnc_freqspec_finalize_real(GObject* fsp)
-{
-}
-
-/*
- * Initializes a FreqSpec by setting it's to type INVALID.
- * Use this to initialise a stack object.
- * FreqSpec objects must be initalised before being used by
- * any other method.
- */
-
-static void
-xaccFreqSpecInit( FreqSpec *fs, QofBook *book )
-{
- g_return_if_fail( fs );
- g_return_if_fail (book);
-
- qof_instance_init_data (&fs->entity, QOF_ID_FREQSPEC, book);
-
- fs->type = INVALID;
- fs->uift = UIFREQ_ONCE;
-
- memset( &(fs->s), 0, sizeof(fs->s) );
-}
-
-FreqSpec*
-xaccFreqSpecMalloc(QofBook *book)
-{
- FreqSpec *fs;
-
- g_return_val_if_fail (book, NULL);
-
- fs = g_object_new(GNC_TYPE_FREQSPEC, NULL);
- xaccFreqSpecInit( fs, book );
- qof_event_gen( &fs->entity, QOF_EVENT_CREATE , NULL);
- return fs;
-}
-
-
-void
-xaccFreqSpecCleanUp( FreqSpec *fs )
-{
- g_return_if_fail( fs );
- switch ( fs->type ) {
- case INVALID:
- case ONCE:
- case DAILY:
- case WEEKLY:
- case MONTHLY:
- case MONTH_RELATIVE:
- break;
- case COMPOSITE:
- xaccFreqSpecCompositesClear( fs );
- g_list_free( fs->s.composites.subSpecs );
- break;
- default:
- g_return_if_fail(FALSE);
- }
- fs->type = INVALID;
-}
-
-void
-xaccFreqSpecFree( FreqSpec *fs )
-{
- if ( fs == NULL ) return;
- qof_event_gen( &fs->entity, QOF_EVENT_DESTROY , NULL);
- xaccFreqSpecCleanUp( fs );
-
- /* qof_instance_release (&fs->entity); */
- g_object_unref( fs );
-}
-
-FreqType
-xaccFreqSpecGetType( FreqSpec *fs )
-{
- g_return_val_if_fail( fs, INVALID );
- /* Is this really a fail? */
- //g_return_val_if_fail( fs->type != INVALID, INVALID );
- return fs->type;
-}
-
-
-UIFreqType
-xaccFreqSpecGetUIType( FreqSpec *fs )
-{
- g_return_val_if_fail( fs, INVALID );
- return fs->uift;
-}
-
-void
-xaccFreqSpecSetUIType( FreqSpec *fs, UIFreqType newUIFreqType )
-{
- g_return_if_fail( fs );
- fs->uift = newUIFreqType;
-}
-
-static inline guint32 min( guint32 a, guint32 b )
-{
- return a > b ? b : a;
-}
-
-void
-xaccFreqSpecGetNextInstance( FreqSpec *fs,
- const GDate* in_date,
- GDate* out_date )
-{
- GList *list;
-
- g_return_if_fail( fs );
- g_return_if_fail( in_date );
- g_return_if_fail( out_date );
- switch( fs->type ) {
- case INVALID:
- /* this is okay, just lame. */
- g_date_clear( out_date, 1 );
- break;
-
- case ONCE:
- if ( g_date_compare( &(fs->s.once.date), in_date ) > 0 )
- {
- *out_date = fs->s.once.date;
- } else {
- /* Date is past due. Return an invalid date. */
- g_date_clear( out_date, 1 );
- }
- break;
-
- case DAILY: {
- guint32 julian_in_date, julian_next_repeat, complete_intervals;
-
- julian_in_date = g_date_get_julian( in_date );
- complete_intervals =
- (julian_in_date - fs->s.daily.offset_from_epoch) /
- fs->s.daily.interval_days;
- julian_next_repeat =
- fs->s.daily.offset_from_epoch +
- (complete_intervals + 1) * fs->s.daily.interval_days;
- g_date_set_julian( out_date, julian_next_repeat );
- } break;
-
- case WEEKLY: {
- /* This implementation stores the offset from epoch as the number
- * of days, not week epoch offset and day in week offset.
- * It is very similar to the daily repeat representation. */
- guint32 julian_in_date, julian_next_repeat, complete_intervals;
-
- julian_in_date = g_date_get_julian( in_date );
- complete_intervals =
- (julian_in_date - fs->s.weekly.offset_from_epoch) /
- (fs->s.weekly.interval_weeks * 7);
- julian_next_repeat =
- fs->s.weekly.offset_from_epoch +
- (complete_intervals + 1) * fs->s.weekly.interval_weeks * 7;
- g_date_set_julian( out_date, julian_next_repeat );
- } break;
-
- case MONTHLY: {
- guint32 in_months_from_epoch, after_repeat_in_month_interval,
- complete_intervals, next_repeat_months_from_epoch, month, year;
-
- in_months_from_epoch = (g_date_get_year( in_date )-1) * 12 +
- g_date_get_month( in_date ) - 1;
- complete_intervals =
- (in_months_from_epoch - fs->s.monthly.offset_from_epoch) /
- fs->s.monthly.interval_months;
- after_repeat_in_month_interval =
- (g_date_get_day( in_date ) >= fs->s.monthly.day_of_month ||
- (in_months_from_epoch - fs->s.monthly.offset_from_epoch) %
- fs->s.monthly.interval_months > 0 ||
- g_date_get_day( in_date ) >=
- g_date_get_days_in_month( g_date_get_month( in_date ),
- g_date_get_year( in_date ) ) ) ? 1 : 0;
- next_repeat_months_from_epoch =
- fs->s.monthly.offset_from_epoch +
- (complete_intervals + after_repeat_in_month_interval) *
- fs->s.monthly.interval_months;
- /* Hmmm... what happens if the day of the month is greater than the
- * number of days in this month?
- * Here I have constrained the day of the month by the number
- * of days in the month. This is compensated for above by checking if
- * the input day is the last day of that month, in which case it will
- * move to the next month interval.
- */
- month = next_repeat_months_from_epoch % 12 + 1;
- year = next_repeat_months_from_epoch / 12 + 1;
- g_date_set_dmy( out_date,
- min( fs->s.monthly.day_of_month,
- g_date_get_days_in_month( month, year ) ),
- month,
- year );
- } break;
-
- case MONTH_RELATIVE: {
- guint32 in_months_from_epoch, after_repeat_in_month_interval,
- complete_intervals, next_repeat_months_from_epoch, month, year,
- wday_of_1st, day_of_repeat;
-
- GDate date1;
- in_months_from_epoch = (g_date_get_year( in_date )-1) * 12 +
- g_date_get_month( in_date ) - 1;
- complete_intervals =
- (in_months_from_epoch - fs->s.month_relative.offset_from_epoch) /
- fs->s.month_relative.interval_months;
- month = g_date_get_month( in_date );
- year = g_date_get_year( in_date );
- g_date_set_dmy( &date1, 1, month, year );
- wday_of_1st = g_date_get_weekday( &date1 );
- day_of_repeat = (fs->s.month_relative.occurrence-1)*7 +
- ((fs->s.month_relative.weekday + 7 - wday_of_1st)%7 + 1);
- after_repeat_in_month_interval =
- (g_date_get_day( in_date ) >= day_of_repeat ||
- day_of_repeat > g_date_get_days_in_month( month, year ) ||
- (in_months_from_epoch - fs->s.month_relative.offset_from_epoch) %
- fs->s.month_relative.interval_months > 0 ) ? 1 : 0;
- next_repeat_months_from_epoch =
- fs->s.month_relative.offset_from_epoch +
- (complete_intervals + after_repeat_in_month_interval) *
- fs->s.month_relative.interval_months;
- month = next_repeat_months_from_epoch % 12 + 1;
- year = next_repeat_months_from_epoch / 12 + 1;
- g_date_set_dmy( &date1, 1, month, year );
- wday_of_1st = g_date_get_weekday( &date1 );
- /* This calculates the day of the month in the month which forms
- * the next month in the cycle after the given input date.
- * However, this day may be larger than the number of days in
- * that month... */
- day_of_repeat = (fs->s.month_relative.occurrence-1)*7 +
- ((fs->s.month_relative.weekday + 7 - wday_of_1st)%7 + 1);
- while( day_of_repeat > g_date_get_days_in_month( month, year ) ) {
- /* If the repeat occurs after the end of the month, then find
- * the next month containing a day which satisfies the
- * request. Each candiate month separated by interval_months
- * is considered by this loop.*/
- ++complete_intervals;
- next_repeat_months_from_epoch =
- fs->s.month_relative.offset_from_epoch +
- complete_intervals * fs->s.month_relative.interval_months;
- month = next_repeat_months_from_epoch % 12 + 1;
- year = next_repeat_months_from_epoch / 12 + 1;
- g_date_set_dmy( &date1, 1, month, year );
- wday_of_1st = g_date_get_weekday( &date1 );
- day_of_repeat = (fs->s.month_relative.occurrence-1)*7 +
- ((fs->s.month_relative.weekday + 7 - wday_of_1st)%7 + 1);
- /* Hmmm... It would be nice to know that this loop is
- * guaranteed to terminate... CHECK ME! */
- }
- g_date_set_dmy( out_date, day_of_repeat, month, year );
- } break;
-
- case COMPOSITE:
- list = fs->s.composites.subSpecs;
- if ( !list ) {
- /* sets date to be invalid */
- g_date_clear( out_date, 1 );
- break;
- }
- {
- /* This implements || composites. */
- guint32 min_julian = 0xFFFFFFFF; /* the biggest unsigned 32 bit number */
- guint32 this_julian;
- do {
- GDate next_repeat;
- xaccFreqSpecGetNextInstance(
- (FreqSpec*) list->data,
- in_date,
- &next_repeat );
- this_julian = g_date_get_julian( &next_repeat );
-
- min_julian = min( min_julian, this_julian );
-
- } while ( (list = g_list_next(list)) );
- g_date_set_julian( out_date, min_julian );
- }
- break;
-
- default:
- g_date_clear( out_date, 1 );
- g_return_if_fail(FALSE);
- }
-}
-
-/*
-char*
-xaccFreqSpecIsValidDateRelaxed( FreqSpec *fs, time_t query )
-{
- return "FIXME: not implemented yet!";
-}
-*/
-
-void
-xaccFreqSpecSetNone( FreqSpec *fs )
-{
- g_return_if_fail( fs );
- xaccFreqSpecCleanUp( fs );
- fs->type = INVALID;
-}
-
-void
-xaccFreqSpecSetOnceDate( FreqSpec *fs, const GDate* when )
-{
- g_return_if_fail( fs );
- g_return_if_fail( when );
- xaccFreqSpecCleanUp( fs );
- fs->type = ONCE;
- fs->s.once.date = *when;
-}
-
-void
-xaccFreqSpecSetDaily( FreqSpec *fs,
- const GDate* initial_date,
- guint interval_days )
-{
- guint32 julian_days_since_epoch;
-
- g_return_if_fail( fs );
- g_return_if_fail( interval_days > 0 );
- xaccFreqSpecCleanUp( fs );
- fs->type = DAILY;
- fs->s.daily.interval_days = interval_days;
-
- julian_days_since_epoch = g_date_get_julian( initial_date );
- fs->s.daily.offset_from_epoch = julian_days_since_epoch % interval_days;
-}
-
-void
-xaccFreqSpecSetWeekly( FreqSpec *fs,
- const GDate* initial_date,
- guint interval_weeks )
-{
-/* pick one... make sure that the code in next matches this,
- * and that the fields in the
- * weekly struct match too.
- */
-#if 0
-/* *
- * This implements weekly by using the fact that 1 week = 7 days.
- * Weeks start at epoch in this representation, not necesarily Monday,
- * so there is not really any difference...
- * The weekly tests pass.
- */
- guint32 julian_days_since_epoch;
-
- g_return_if_fail( fs );
- g_return_if_fail( interval_weeks > 0 );
- xaccFreqSpecCleanUp( fs );
-
- fs->type = DAILY;
- fs->s.daily.interval_days = 7 * interval_weeks;
-
- julian_days_since_epoch = g_date_get_julian( initial_date );
- fs->s.daily.offset_from_epoch = julian_days_since_epoch % (7*interval_weeks);
-#endif
-#if 1
- /* simplest solution */
- guint32 julian_days_since_epoch;
-
- g_return_if_fail( fs );
- g_return_if_fail( interval_weeks > 0 );
- xaccFreqSpecCleanUp( fs );
-
- fs->type = WEEKLY;
- fs->s.weekly.interval_weeks = interval_weeks;
-
- julian_days_since_epoch = g_date_get_julian( initial_date );
- fs->s.weekly.offset_from_epoch = julian_days_since_epoch % (7*interval_weeks);
-#endif
-#if 0
-/**
- * Use the weekly implementation, which seems to be more complicated...
- * uses separate weekly and day in week offsets.
- * works.
- */
- guint32 julian_day_initial, weeks_since_epoch;
-
- g_return_if_fail( fs );
- g_return_if_fail( interval_weeks > 0 );
- xaccFreqSpecCleanUp( fs );
-
- fs->type = WEEKLY;
- fs->s.weekly.interval_weeks = interval_weeks;
-
- julian_day_initial = g_date_get_julian( initial_date );
- weeks_since_epoch = (julian_day_initial-1) / 7;
- fs->s.weekly.day_of_week = (julian_day_initial-1) % 7;
- fs->s.weekly.offset_from_epoch = weeks_since_epoch % interval_weeks;
-
- g_return_if_fail( 0 <= fs->s.weekly.day_of_week );
- g_return_if_fail( fs->s.weekly.day_of_week < 7 );
- g_return_if_fail( fs->s.weekly.offset_from_epoch < interval_weeks );
- g_return_if_fail( 0 <= fs->s.weekly.offset_from_epoch );
-#endif
-}
-
-void
-xaccFreqSpecSetMonthly( FreqSpec *fs,
- const GDate* initial_date,
- guint interval_months )
-{
- guint months_since_epoch;
- g_return_if_fail( fs );
- g_return_if_fail( interval_months > 0 );
- xaccFreqSpecCleanUp( fs );
- fs->type = MONTHLY;
- fs->s.monthly.interval_months = interval_months;
-
- months_since_epoch = (g_date_get_year( initial_date )-1) * 12 +
- g_date_get_month( initial_date ) - 1;
- fs->s.monthly.offset_from_epoch = months_since_epoch % interval_months;
- fs->s.monthly.day_of_month = g_date_get_day( initial_date );
-
- g_return_if_fail( fs->s.monthly.offset_from_epoch <
- fs->s.monthly.interval_months );
-}
-
-void
-xaccFreqSpecSetMonthRelative( FreqSpec *fs,
- const GDate* initial_date,
- guint interval_months )
-{
- guint months_since_epoch;
- g_return_if_fail( fs );
- g_return_if_fail( interval_months > 0 );
- xaccFreqSpecCleanUp( fs );
- fs->type = MONTH_RELATIVE;
- fs->s.month_relative.interval_months = interval_months;
-
- months_since_epoch = (g_date_get_year( initial_date )-1) * 12 +
- g_date_get_month( initial_date ) - 1;
- fs->s.month_relative.offset_from_epoch = months_since_epoch % interval_months;
-
- fs->s.month_relative.weekday = g_date_get_weekday( initial_date );
- fs->s.month_relative.occurrence = (g_date_get_day( initial_date )-1) / 7 + 1;
-
- g_return_if_fail( fs->s.month_relative.weekday > 0 );
- g_return_if_fail( fs->s.month_relative.weekday <= 7 );
- g_return_if_fail( fs->s.month_relative.occurrence > 0 );
- g_return_if_fail( fs->s.month_relative.occurrence <= 5 );
- g_return_if_fail( fs->s.month_relative.offset_from_epoch <
- fs->s.month_relative.interval_months );
-}
-
-void
-xaccFreqSpecSetComposite( FreqSpec *fs )
-{
- g_return_if_fail( fs );
- xaccFreqSpecCleanUp( fs );
- fs->type = COMPOSITE;
- fs->s.composites.subSpecs = NULL;
-}
-
-int
-xaccFreqSpecGetOnce( FreqSpec *fs, GDate *outGD )
-{
- if ( fs->type != ONCE )
- return -1;
- *outGD = fs->s.once.date;
- return 0;
-}
-
-int
-xaccFreqSpecGetDaily( FreqSpec *fs, int *outRepeat )
-{
- if ( fs->type != DAILY )
- return -1;
- *outRepeat = fs->s.daily.interval_days;
- return 0;
-}
-
-int
-xaccFreqSpecGetWeekly( FreqSpec *fs, int *outRepeat, int *outDayOfWeek )
-{
- if ( fs->type != WEEKLY )
- return -1;
- *outRepeat = fs->s.weekly.interval_weeks;
- *outDayOfWeek = fs->s.weekly.offset_from_epoch % 7;
- return 0;
-}
-
-int
-xaccFreqSpecGetMonthly( FreqSpec *fs, int *outRepeat, int *outDayOfMonth, int *outMonthOffset )
-{
- if ( fs->type != MONTHLY )
- return -1;
- *outRepeat = fs->s.monthly.interval_months;
- *outDayOfMonth = fs->s.monthly.day_of_month;
- *outMonthOffset = fs->s.monthly.offset_from_epoch;
- return 0;
-}
-
-GList*
-xaccFreqSpecCompositeGet( FreqSpec *fs )
-{
- g_return_val_if_fail( fs, NULL );
- g_return_val_if_fail( fs->type == COMPOSITE, NULL );
- return fs->s.composites.subSpecs;
-}
-
-void
-xaccFreqSpecCompositeAdd( FreqSpec *fs, FreqSpec *fsToAdd )
-{
- g_return_if_fail( fs );
- g_return_if_fail( fs->type == COMPOSITE );
- fs->s.composites.subSpecs =
- g_list_append( fs->s.composites.subSpecs, fsToAdd );
-}
-
-void
-subSpecsListMapDelete( gpointer data, gpointer user_data )
-{
- xaccFreqSpecFree( (FreqSpec*)data );
-}
-
-void
-xaccFreqSpecCompositesClear( FreqSpec *fs )
-{
- g_return_if_fail( fs->type == COMPOSITE );
- g_list_foreach( fs->s.composites.subSpecs,
- subSpecsListMapDelete, NULL );
-}
-
-static GString *
-get_dom_string(guint dom)
-{
- GString *str = g_string_new(NULL);
-
- if(dom > 31)
- {
- /* This is displayed instead of the number of the day of month. */
- g_string_printf(str, _( "last day"));
- }
- else
- {
- g_string_printf(str, "%u", dom);
- }
-
- return str;
-}
-
-static const char*
-qofFreqSpecPrintable (gpointer obj)
-{
- FreqSpec *fs;
- GString *str;
-
- fs = (FreqSpec*)obj;
- g_return_val_if_fail(fs != NULL, NULL);
- str = g_string_new("");
- xaccFreqSpecGetFreqStr(fs, str);
- return str->str;
-}
-
-void
-xaccFreqSpecGetFreqStr( FreqSpec *fs, GString *str )
-{
- GList *list;
- FreqSpec *tmpFS;
- int tmpInt;
- char *tmpStr;
- int i;
-#define MAX_FREQ_STR_SIZE 127
- char freqStrBuf[ MAX_FREQ_STR_SIZE + 1];
-
- memset( freqStrBuf, 0, MAX_FREQ_STR_SIZE + 1 );
-
- switch( xaccFreqSpecGetUIType( fs ) ) {
- case UIFREQ_NONE:
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("None") );
- break;
-
- case UIFREQ_ONCE:
- tmpStr = g_new0( char, GDATE_STRING_BUF_SIZE );
- /* this is now a GDate. */
- g_date_strftime( tmpStr, GDATE_STRING_SIZE,
- "%x",
- &fs->s.once.date );
- /* %s is the strftime-string of the one-time date. */
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("Once: %s"), tmpStr );
- g_free( tmpStr );
- break;
-
- case UIFREQ_DAILY:
- if ( fs->s.daily.interval_days > 1 )
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the number of intervals */
- _("Daily (x%u)"),
- fs->s.daily.interval_days );
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("Daily") );
- }
- break;
-
- case UIFREQ_DAILY_MF:
- {
- FreqSpec *subFS;
- if ( g_list_length( fs->s.composites.subSpecs ) != 5 ) {
- g_critical("Invalid Daily[M-F] structure");
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- "Daily[M-F]: error" );
- return;
- }
- /* We assume that all of the weekly FreqSpecs that make up
- the Daily[M-F] FreqSpec have the same interval. */
- subFS = (FreqSpec*)fs->s.composites.subSpecs->data;
-
- if ( subFS->s.weekly.interval_weeks > 1 ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the number of intervals */
- _("Weekdays: (x%u)"),
- subFS->s.weekly.interval_weeks );
- }
- else
- {
- snprintf(freqStrBuf, MAX_FREQ_STR_SIZE, _("Weekdays"));
- }
-
- }
- break;
-
- case UIFREQ_WEEKLY:
-
- tmpInt = -1;
- tmpStr = g_new0( char, 8 );
- for ( i=0; i<7; i++ ) {
- tmpStr[i] = '-';
- }
-
-
- for ( list = xaccFreqSpecCompositeGet( fs );
- list; list = list->next ) {
- int dowIdx;
-
- tmpFS = (FreqSpec*)list->data;
- if ( xaccFreqSpecGetType(tmpFS) != WEEKLY ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- "error: UIFREQ_WEEKLY doesn't contain weekly children" );
- g_free( tmpStr );
- return;
- }
- if ( tmpInt == -1 ) {
- tmpInt = tmpFS->s.weekly.interval_weeks;
- }
- /* put the first letter of the weekday name in
- the appropriate position. */
- dowIdx = tmpFS->s.weekly.offset_from_epoch % 7;
- tmpStr[dowIdx] = *(get_wday_name(dowIdx));
- }
-
- if ( tmpInt > 1 ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %d are the number of intervals; %s is
- the name of the weekday */
- _( "Weekly (x%d): %s"), tmpInt, tmpStr );
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* Translators: %s is the name of the weekday */
- _( "Weekly: %s"), tmpStr );
- }
- g_free( tmpStr );
- break;
-
- case UIFREQ_BI_WEEKLY:
- /* %s is the name of the weekday */
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("Bi-Weekly, %ss"),
- get_wday_name(fs->s.weekly.offset_from_epoch % 7) );
- break;
-
- case UIFREQ_SEMI_MONTHLY:
- {
- GString *first_dom, *second_dom;
-
- list = xaccFreqSpecCompositeGet( fs );
- tmpFS = (FreqSpec*)(g_list_nth( list, 0 )->data);
-
- first_dom = get_dom_string(tmpFS->s.monthly.day_of_month);
-
- tmpFS = (FreqSpec*)(g_list_nth( list, 1 )->data);
- second_dom = get_dom_string(tmpFS->s.monthly.day_of_month);
-
-
- if ( tmpFS->s.monthly.interval_months > 1 ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* Translators: %u is the number of intervals;
- %s is the day of month of the starting month
- (or the string "last day"); %s is the day of
- month of the ending month */
- _("Semi-monthly (x%u): %s, %s"),
- tmpFS->s.monthly.interval_months,
- first_dom->str,
- second_dom->str);
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* Translators: %s is the day of month of the
- starting month (or the string "last day"); %s
- is the day of month of the ending month */
- _("Semi-monthly: %s, %s"),
- first_dom->str,
- second_dom->str);
- }
- g_string_free(first_dom, TRUE);
- g_string_free(second_dom, TRUE);
-
- break;
- }
-
- case UIFREQ_MONTHLY:
-
- if ( fs->s.monthly.interval_months > 1 ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the number of intervals; %u is
- the day of month */
- _("Monthly (x%u): %u"),
- fs->s.monthly.interval_months,
- fs->s.monthly.day_of_month);
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the day of month */
- _("Monthly: %u"),
- fs->s.monthly.day_of_month );
- }
- break;
-
- case UIFREQ_QUARTERLY:
- if ( fs->s.monthly.interval_months != 3 ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the number of intervals; %u is
- the day of month */
- _("Quarterly (x%u): %u"),
- fs->s.monthly.interval_months/3,
- fs->s.monthly.day_of_month);
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the day of month */
- _("Quarterly: %u"),
- fs->s.monthly.day_of_month );
- }
- break;
-
- case UIFREQ_TRI_ANUALLY:
-
- if ( fs->s.monthly.interval_months != 4 ) {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the number of intervals; %u is
- the day of month */
- _("Tri-Yearly (x%u): %u"),
- fs->s.monthly.interval_months/4,
- fs->s.monthly.day_of_month);
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the day of month */
- _("Tri-Yearly: %u"),
- fs->s.monthly.day_of_month );
- }
- break;
-
- case UIFREQ_SEMI_YEARLY:
- if ( fs->s.monthly.interval_months != 6 ) {
- if ( (fs->s.monthly.interval_months % 6) != 0 ) {
- g_critical( "FreqSpec Semi-Yearly month-interval "
- "is not a multiple of 6 [%d]",
- fs->s.monthly.interval_months );
- }
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the number of intervals; %u
- is the day of month */
- _("Semi-Yearly (x%u): %u"),
- fs->s.monthly.interval_months/6,
- fs->s.monthly.day_of_month);
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %u is the day of month */
- _("Semi-Yearly: %u"),
- fs->s.monthly.day_of_month );
- }
- break;
-
- case UIFREQ_YEARLY:
- if ( fs->s.monthly.interval_months != 12 ) {
- if ( (fs->s.monthly.interval_months % 12) != 0 ) {
- g_critical( "Yearly FreqSpec month-interval "
- "is not a multiple of 12 [%d]",
- fs->s.monthly.interval_months );
- }
-
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* FIXME: This string *must* be translated for
- en_GB, en_AU and everywhere else with the
- sensible ordering of ddmmyy. Translators
- note: to switch the last two arguments,
- write "Yearly (x%1$u): %3$u of month %2$s"
-
- %u is the number of intervals; %s is the
- abbreviated name of the month; %u is the
- day of month. */
- _("Yearly (x%u): %s/%u"),
- fs->s.monthly.interval_months/12,
- get_abbrev_month_name(fs->s.monthly.offset_from_epoch),
- fs->s.monthly.day_of_month);
- }
- else
- {
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE,
- /* %s is the abbreviated name of the
- month; %u is the day of month */
- _("Yearly: %s/%u"),
- get_abbrev_month_name(fs->s.monthly.offset_from_epoch),
- fs->s.monthly.day_of_month );
- }
- break;
-
- default:
- snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("Unknown") );
- break;
- }
- g_string_printf( str, "%s", freqStrBuf );
-}
-
-static
-int
-int_cmp( int a, int b )
-{
- if ( a < b )
- return -1;
- if ( a == b )
- return 0;
- return 1;
-}
-
-/*
- * Returns the "min" FreqSpec sub-element of a composite FreqSpec.
- */
-static
-FreqSpec*
-_gnc_freq_spec_get_min( FreqSpec *fs )
-{
- FreqSpec *toRet, *tmpFS;
- GList *l;
-
- g_assert( xaccFreqSpecGetType(fs) == COMPOSITE );
- toRet = NULL;
- for ( l = xaccFreqSpecCompositeGet(fs);
- l;
- l = l->next ) {
- tmpFS = (FreqSpec*)l->data;
-
- if ( toRet == NULL ) {
- toRet = tmpFS;
- continue;
- }
-
- if ( gnc_freq_spec_compare( toRet, tmpFS ) > 0 ) {
- toRet = tmpFS;
- }
- }
- return toRet;
-}
-
-int
-gnc_freq_spec_compare( FreqSpec *a, FreqSpec *b )
-{
- FreqType fta, ftb;
- int tmpInt;
-
- if ( ! (a && b) ) {
- return 0;
- } else if ( !a && b ) {
- return 1;
- } else if ( a && !b ) {
- return -1;
- } /* else { this else intentionally left blank; both-valid code is
- * below. } */
-
- fta = xaccFreqSpecGetType( a );
- ftb = xaccFreqSpecGetType( b );
-
- if ( fta == COMPOSITE ) {
- a = _gnc_freq_spec_get_min( a );
- fta = xaccFreqSpecGetType( a );
- }
- if ( ftb == COMPOSITE ) {
- b = _gnc_freq_spec_get_min( b );
- ftb = xaccFreqSpecGetType( b );
- }
-
- if ( fta < ftb ) {
- return -1;
- } else if ( fta > ftb ) {
- return 1;
- } /* else { this else intentionally left blank; '='-case code is
- * below. */
-
- switch ( fta /* == ftb */ ) {
- case INVALID:
- return 0;
- break;
- case ONCE:
- return g_date_compare( &a->s.once.date,
- &b->s.once.date );
- break;
- case DAILY:
- tmpInt = int_cmp( a->s.daily.interval_days,
- b->s.daily.interval_days );
- if ( tmpInt != 0 ) {
- return tmpInt;
- }
- return int_cmp( a->s.daily.offset_from_epoch,
- b->s.daily.offset_from_epoch );
- break;
- case WEEKLY:
- tmpInt = int_cmp( a->s.weekly.interval_weeks,
- b->s.weekly.interval_weeks );
- if ( tmpInt != 0 ) {
- return tmpInt;
- }
- return int_cmp( a->s.weekly.offset_from_epoch,
- b->s.weekly.offset_from_epoch );
- break;
- case MONTHLY:
- tmpInt = int_cmp( a->s.monthly.interval_months,
- b->s.monthly.interval_months );
- if ( tmpInt != 0 ) {
- return tmpInt;
- }
- return int_cmp( a->s.monthly.day_of_month,
- b->s.monthly.day_of_month );
- break;
- case MONTH_RELATIVE:
- g_error( "MONTH-RELATIVE dates not supported." );
- break;
- case COMPOSITE:
- /* We shouldn't see a composite after doing the
- * composite-reduction above. */
- g_error( "This code should not be reached." );
- break;
- default:
- g_error( "Unknown freqspec type %d", fta );
- break;
- }
- return 0;
-}
-
-/* QOF routines. */
-
-static int
-qofFreqSpecGetMonthDay(FreqSpec *fs)
-{
- int outDayOfMonth;
-
- outDayOfMonth = 0;
- if ( fs->type != MONTHLY ) { return outDayOfMonth; }
- outDayOfMonth = fs->s.monthly.day_of_month;
- return outDayOfMonth;
-}
-/*
-static int
-qofFreqSpecGetMonthOffset(FreqSpec *fs)
-{
- int outMonthOffset;
-
- outMonthOffset = 0;
- if ( fs->type != MONTHLY ) { return outMonthOffset; }
- outMonthOffset = fs->s.monthly.offset_from_epoch;
- return outMonthOffset;
-}
-*/
-static Timespec
-qofFreqSpecGetBaseDate(FreqSpec *fs)
-{
- GDate *when;
- struct tm number;
- time_t start_t;
- Timespec ts = {0,0};
-
- g_return_val_if_fail( fs != NULL , ts);
- when = g_date_new();
- if(xaccFreqSpecGetOnce(fs, when) == -1) { return ts; }
- g_date_to_struct_tm(when, &number);
- start_t = mktime(&number);
- timespecFromTime_t(&ts, start_t);
- return ts;
-}
-
-static char*
-qofFreqSpecGetUIType(FreqSpec *fs)
-{
- char *type_string;
-
- g_return_val_if_fail(fs, NULL);
- type_string = g_strdup(UIFreqTypeasString(fs->uift));
- return type_string;
-}
-
-static int
-qofFreqSpecGetRepeat(FreqSpec *fs)
-{
- int repeat, dump, dump2;
-
- g_return_val_if_fail(fs != NULL, -1);
- repeat = -1;
- dump = dump2 = 0;
- switch(xaccFreqSpecGetType(fs))
- {
- case INVALID: {
- break;
- }
- case ONCE: {
- repeat = 0;
- break;
- }
- case DAILY: {
- xaccFreqSpecGetDaily(fs, &repeat);
- break;
- }
- case WEEKLY: {
- xaccFreqSpecGetWeekly(fs, &repeat, &dump);
- break;
- }
- case MONTHLY: {
- xaccFreqSpecGetMonthly(fs, &repeat, &dump, &dump2);
- break;
- }
- case MONTH_RELATIVE: {
- repeat = 0;
- break;
- }
- case COMPOSITE: {
- repeat = 0;
- break;
- }
- default: {
- break;
- }
- }
- return repeat;
-}
-
-/* QOF set routines - may look a little strange as QOF can set parameters in any order. */
-/* Initial state: UIFREQ_ONCE, INVALID, union s memset to zero and value == 0 */
-
-static void
-qofFreqSpecCalculate(FreqSpec *fs, gint value)
-{
- GDate *when;
-
- g_return_if_fail(fs != NULL);
- /* If it's INVALID, nothing can be done until more data is set. */
- if(xaccFreqSpecGetType(fs) == INVALID) { return; }
- /* If it's still UIFREQ_ONCE, nothing needs to be done */
- if(xaccFreqSpecGetUIType(fs) == UIFREQ_ONCE) { return; }
- /* If value is zero, nothing needs to be done. */
- if(value == 0) { return; }
- when = g_date_new();
- xaccFreqSpecGetOnce(fs, when);
- switch (xaccFreqSpecGetUIType(fs)) {
- case UIFREQ_NONE : {
- xaccFreqSpecSetNone(fs);
- }
- break;
- case UIFREQ_ONCE : {
- /* should be impossible but just to be sure. */
- break;
- }
- case UIFREQ_DAILY : {
- xaccFreqSpecSetDaily(fs, when, value);
- break;
- }
- case UIFREQ_DAILY_MF : {
-
- break;
- }
- case UIFREQ_WEEKLY : {
- xaccFreqSpecSetWeekly(fs, when, value);
- break;
- }
- case UIFREQ_BI_WEEKLY : {
-
- break;
- }
- case UIFREQ_SEMI_MONTHLY : {
-
- break;
- }
- case UIFREQ_MONTHLY : {
- xaccFreqSpecSetMonthly(fs, when, value);
- break;
- }
- case UIFREQ_QUARTERLY : {
-
- break;
- }
- case UIFREQ_TRI_ANUALLY : {
-
- break;
- }
- case UIFREQ_SEMI_YEARLY : {
-
- break;
- }
- case UIFREQ_YEARLY : {
-
- break;
- }
- default: { break; }
- }
-}
-
-static void
-qofFreqSpecSetUIType (FreqSpec *fs, const char *type_string)
-{
- g_return_if_fail(fs != NULL);
- xaccFreqSpecSetUIType(fs, UIFreqTypefromString(type_string));
- qofFreqSpecCalculate(fs, fs->value);
-}
-
-static void
-qofFreqSpecSetBaseDate(FreqSpec *fs, Timespec start_date)
-{
- time_t start_t;
- FreqType type;
- GDate *when;
-
- g_return_if_fail( fs != NULL );
- when = g_date_new();
- type = xaccFreqSpecGetType(fs);
- start_t = timespecToTime_t(start_date);
- g_date_set_time_t(when, start_t);
- /* QOF sets this before a type is assigned. */
- if(type == INVALID) {
- fs->type = ONCE;
- }
- xaccFreqSpecSetOnceDate(fs, when);
- /* Now we have a GDate available for the calculation. */
- qofFreqSpecCalculate(fs, fs->value);
-}
-
-static void
-qofFreqSpecSetRepeat(FreqSpec *fs, gint value)
-{
- fs->value = value;
- qofFreqSpecCalculate(fs, value);
-}
-
-static QofObject FreqSpecDesc =
-{
- interface_version : QOF_OBJECT_VERSION,
- e_type : QOF_ID_FREQSPEC,
- type_label : "Frequency Specification",
- create : (gpointer)xaccFreqSpecMalloc,
- book_begin : NULL,
- book_end : NULL,
- is_dirty : NULL,
- mark_clean : NULL,
- foreach : qof_collection_foreach,
- printable : qofFreqSpecPrintable,
- version_cmp : (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
-};
-
-gboolean FreqSpecRegister (void)
-{
- static QofParam params[] = {
- { FS_UI_TYPE, QOF_TYPE_STRING, (QofAccessFunc)qofFreqSpecGetUIType, (QofSetterFunc)qofFreqSpecSetUIType },
- { FS_REPEAT, QOF_TYPE_INT64, (QofAccessFunc)qofFreqSpecGetRepeat, (QofSetterFunc)qofFreqSpecSetRepeat },
- { FS_BASE_DATE, QOF_TYPE_DATE, (QofAccessFunc)qofFreqSpecGetBaseDate,
- (QofSetterFunc)qofFreqSpecSetBaseDate },
- { FS_MONTH_DAY, QOF_TYPE_STRING, (QofAccessFunc)qofFreqSpecGetMonthDay, NULL },
- { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
- { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
- { NULL },
- };
- qof_class_register(QOF_ID_FREQSPEC, (QofSortFunc)gnc_freq_spec_compare, params);
- return qof_object_register(&FreqSpecDesc);
-}
Deleted: gnucash/branches/gda-dev/src/engine/FreqSpecP.h
===================================================================
--- gnucash/branches/gda-dev/src/engine/FreqSpecP.h 2007-11-11 17:32:56 UTC (rev 16593)
+++ gnucash/branches/gda-dev/src/engine/FreqSpecP.h 2007-11-11 21:54:43 UTC (rev 16594)
@@ -1,99 +0,0 @@
-/********************************************************************\
- * FreqSpec.h -- Frequency Specification *
- * Copyright (C) 2001 Joshua Sled <jsled at asynchronous.org> *
- * Copyright (C) 2001 Ben Stanley <bds02 at uow.edu.au> *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License as *
- * published by the Free Software Foundation; either version 2 of *
- * the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License*
- * along with this program; if not, contact: *
- * *
- * Free Software Foundation Voice: +1-617-542-5942 *
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
- * Boston, MA 02110-1301, USA gnu at gnu.org *
- * *
-\********************************************************************/
-
-/* *******************************************************************\
-This file contains private definitions and should not be used by
-other parts of the engine. This is private data and is subject to
-change.
-Currently the only files which include this file are:
- FreqSpec.c
- gnc-freqspec-xml-v2.c
-\********************************************************************/
-#ifndef XACC_FREQSPECP_H
-#define XACC_FREQSPECP_H
-
-#include "FreqSpec.h"
-
-struct gncp_freq_spec
-{
- QofInstance entity;
- FreqType type;
- UIFreqType uift;
- union u {
- struct {
- /* The date on which the single event occurs. */
- GDate date;
- } once;
- struct {
- /* number of days from one repeat to the next. */
- guint interval_days;
- /* epoch is defined by glib to be 1/1/1. Offset
- measured in days. 0 <= offset < interval */
- guint offset_from_epoch;
- } daily;
- struct {
- /* A week here is measured as 7 days. The first week starts at epoch.
- * 1/1/1 was a ?. */
-
- /* number of weeks from one repeat to the next. */
- guint interval_weeks;
- /* offset measured in days. This combines the week
- * offset and the day of the week offset. */
- guint offset_from_epoch;
- /* guint offset_from_epoch;*/ /* offset measured in weeks, 0 <= offset < interval */
- /* guint day_of_week;*/ /* I'm not sure what days each value represents, but it's not important. */
- } weekly;
- struct {
- /* number of months from one repeat to the next. */
- guint interval_months;
- /* offset measured in months */
- guint offset_from_epoch;
- /* Which day of the month it occurs on. */
- guint day_of_month;
- } monthly;
- struct {
- /* Number of months from one repeat to the next. */
- guint interval_months;
- /* offset measured in months */
- guint offset_from_epoch;
- /* stores a value equivalent to a GDateWeekday. */
- guint weekday;
- /* the 1st occurrence to the 5th occurrence. */
- guint occurrence;
- } month_relative;
- struct {
- /* A list of specs for a composite freq. */
- GList *subSpecs;
- } composites;
- } s;
- /* temporary storage for QOF */
- gint value;
-};
-
-struct _FreqSpecClass
-{
- QofInstanceClass parent_class;
-};
-
-#endif /* XACC_FREQSPECP_H */
More information about the gnucash-changes
mailing list