r15399 - gnucash/trunk - Fold branches/sx-cleanup/ [14463:14917] back into trunk/.
Josh Sled
jsled at cvs.gnucash.org
Fri Jan 19 18:45:56 EST 2007
Author: jsled
Date: 2007-01-19 18:45:45 -0500 (Fri, 19 Jan 2007)
New Revision: 15399
Trac: http://svn.gnucash.org/trac/changeset/15399
Added:
gnucash/trunk/src/app-utils/gnc-sx-instance-model.c
gnucash/trunk/src/app-utils/gnc-sx-instance-model.h
gnucash/trunk/src/app-utils/test/test-sx.c
gnucash/trunk/src/doc/sx.rst
gnucash/trunk/src/gnome-utils/gnc-dense-cal-model.c
gnucash/trunk/src/gnome-utils/gnc-dense-cal-model.h
gnucash/trunk/src/gnome-utils/gnc-dense-cal-store.c
gnucash/trunk/src/gnome-utils/gnc-dense-cal-store.h
gnucash/trunk/src/gnome-utils/gnc-sx-instance-dense-cal-adapter.c
gnucash/trunk/src/gnome-utils/gnc-sx-instance-dense-cal-adapter.h
gnucash/trunk/src/gnome-utils/test/test-sx.c
gnucash/trunk/src/gnome/dialog-sx-editor.c
gnucash/trunk/src/gnome/dialog-sx-editor.h
gnucash/trunk/src/gnome/dialog-sx-since-last-run.c
gnucash/trunk/src/gnome/dialog-sx-since-last-run.h
gnucash/trunk/src/gnome/gnc-plugin-page-sx-list.c
gnucash/trunk/src/gnome/gnc-plugin-page-sx-list.h
gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.c
gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.h
gnucash/trunk/src/gnome/ui/gnc-plugin-page-sx-list-ui.xml
Removed:
gnucash/trunk/src/gnome/dialog-scheduledxaction.c
gnucash/trunk/src/gnome/dialog-scheduledxaction.h
gnucash/trunk/src/gnome/dialog-sxsincelast.c
gnucash/trunk/src/gnome/dialog-sxsincelast.h
Modified:
gnucash/trunk/ChangeLog
gnucash/trunk/src/app-utils/Makefile.am
gnucash/trunk/src/app-utils/test/
gnucash/trunk/src/app-utils/test/Makefile.am
gnucash/trunk/src/app-utils/test/test-exp-parser.c
gnucash/trunk/src/backend/file/io-gncxml-v2.c
gnucash/trunk/src/core-utils/gnc-glib-utils.c
gnucash/trunk/src/core-utils/gnc-glib-utils.h
gnucash/trunk/src/engine/SX-book-p.h
gnucash/trunk/src/engine/SX-book.c
gnucash/trunk/src/engine/SX-book.h
gnucash/trunk/src/engine/SchedXaction.c
gnucash/trunk/src/engine/SchedXaction.h
gnucash/trunk/src/engine/gnc-engine.h
gnucash/trunk/src/engine/test-core/test-engine-stuff.c
gnucash/trunk/src/engine/test-core/test-engine-stuff.h
gnucash/trunk/src/engine/test/test-freq-spec.c
gnucash/trunk/src/engine/test/test-transaction-voiding.c
gnucash/trunk/src/gnome-utils/Makefile.am
gnucash/trunk/src/gnome-utils/gnc-dense-cal.c
gnucash/trunk/src/gnome-utils/gnc-dense-cal.h
gnucash/trunk/src/gnome-utils/gnc-frequency.c
gnucash/trunk/src/gnome-utils/test/
gnucash/trunk/src/gnome-utils/test/Makefile.am
gnucash/trunk/src/gnome/Makefile.am
gnucash/trunk/src/gnome/dialog-sx-from-trans.c
gnucash/trunk/src/gnome/druid-loan.c
gnucash/trunk/src/gnome/glade/sched-xact.glade
gnucash/trunk/src/gnome/gnc-plugin-basic-commands.c
gnucash/trunk/src/gnome/gnc-split-reg.c
gnucash/trunk/src/gnome/top-level.c
gnucash/trunk/src/gnome/ui/Makefile.am
Log:
Fold branches/sx-cleanup/ [14463:14917] back into trunk/.
Modified: gnucash/trunk/ChangeLog
===================================================================
--- gnucash/trunk/ChangeLog 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/ChangeLog 2007-01-19 23:45:45 UTC (rev 15399)
@@ -77,6 +77,17 @@
relocation of previously compiled-in paths. With the exception of
the env variables in src/bin/gnucash, we're fully relocatable now.
+2006-09-16 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome/gnc-plugin-page-sx-list.c (sxsl_get_sx_vars): Add
+ variable extraction to instance-model creation. The
+ GncSxInstances now has a hashtable of variables parsed from the
+ formula, and the GncSxInstance has a copy of that variables hash.
+ Not finished, but mostly in place.
+
+ * src/gnome/dialog-sx-since-last-run.c: New, simplified version of
+ the since-last-run dialog. GncSxSlrTreeModelAdapter.
+
2006-09-13 Christian Stimming <stimming at tuhh.de>
* src/import-export/hbci/gnc-plugin-hbci.c: Move the MT940
@@ -270,6 +281,30 @@
preferences_dialog->Windows. Move "Show close button on notebook
tabs" from General to Windows. Fixes #340299.
+2006-07-27 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome-utils/gnc-dense-cal.c
+ (gnc_dense_cal_transient_model_new): Actually implement
+ GncDenseCalTransientModel.
+
+ * src/gnome/dialog-sx-editor.c (gnc_sxed_update_cal):
+ * src/gnome/dialog-sx-from-trans.c (sxftd_update_example_cal):
+ Use GncDenseCalTransientModel from previous ad-hoc updaters.
+
+
+2006-07-25 Joshua Sled <jsled at asynchronous.org>
+
+ * src/gnome-utils/gnc-dense-cal.c:
+ Add GncDenseCalModel interface, support.
+ Add unfinished GncDenseCalTransient model impl. for
+ one-off being-edited-SX calendar usage.
+
+ * src/gnome/gnc-plugin-page-sx-list.c:
+ Add GncSxInstanceDenseCalAdapter between GncSxInstanceModel and
+ GncDenseCalModel. Start to hook up 'added' and 'removing' signals
+ on the GncSxInstanceModel. The SX-List dense-cal works again, and
+ reflects both removed and new SXes.
+
2006-07-24 Derek Atkins <derek at ihtfp.com>
* [lots of Makefile.am files]:
@@ -302,6 +337,27 @@
extra de-quoting of path names that is done on the GNC_MODULE_PATH
env variable.
+2006-07-16 Joshua Sled <jsled at asynchronous.org>
+
+ * src/engine/SX-book-p.h:
+ * src/engine/SX-book.h:
+ * src/engine/SX-book.c: Promote SX list from a GList to a
+ `SchedXactions` QOF Entity. Create add/remove API that emits
+ GNC_EVENT_{INSERT,REMOVE} signals. Correctly associate the SX
+ List with the collection of SchedXaction qof-type rather than the
+ SX template transactions qof-type. Remove some (now-)dead
+ code. Fix long-standing bug in registration of SX qof types.
+
+ * src/gnome/dialog-sx-editor.[ch]:
+ * src/gnome/dialog-schedxaction.[ch]:
+ Move the SX editor dialog subset of dialog-schedxaction to
+ dialog-sx-editor.[ch].
+
+ * src/gnome/gnc-plugin-page-sx-list.c:
+ Hookup SX editor for both 'new' and 'edit' actions. Hookup
+ row-activation from tree-view. Extend GncSxInstanceModel to
+ support SchedXactions (sx list) modification events.
+
2006-07-16 Derek Atkins <derek at ihtfp.com>
* configure.in:
@@ -331,6 +387,18 @@
* src/gnome-utils/gnc-main-window.c: Do not move windows on
restoration that would be offscreen.
+2006-07-15 Joshua Sled <jsled at asynchronous.org>
+
+ * src/engine/SchedXaction.h (GNC_IS_SX,GNC_SX): added for convenience.
+
+ * src/gnome/ui/gnc-plugin-page-sx-list-ui.xml:
+ * src/gnome/gnc-plugin-page-sx-list.[ch]: SX List as a plugin page.
+
+ * src/gnome/gnc-plugin-basic-commands.c: Call SX List plugin page,
+ not dialog.
+
+ * src/doc/sx.rst: Added.
+
2006-07-15 Derek Atkins <derek at ihtfp.com>
* src/business/business-core/gncAddress.[ch]:
Modified: gnucash/trunk/src/app-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/app-utils/Makefile.am 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/app-utils/Makefile.am 2007-01-19 23:45:45 UTC (rev 15399)
@@ -34,6 +34,7 @@
gnc-exp-parser.c \
gnc-gettext-util.c \
gnc-helpers.c \
+ gnc-sx-instance-model.c \
gncmod-app-utils.c \
gnc-ui-util.c \
guile-util.c \
@@ -59,6 +60,7 @@
gnc-exp-parser.h \
gnc-gettext-util.h \
gnc-helpers.h \
+ gnc-sx-instance-model.h \
gnc-ui-common.h \
gnc-ui-util.h \
guile-util.h \
Copied: gnucash/trunk/src/app-utils/gnc-sx-instance-model.c (from rev 15384, gnucash/branches/sx-cleanup/src/app-utils/gnc-sx-instance-model.c)
Copied: gnucash/trunk/src/app-utils/gnc-sx-instance-model.h (from rev 15384, gnucash/branches/sx-cleanup/src/app-utils/gnc-sx-instance-model.h)
Property changes on: gnucash/trunk/src/app-utils/test
___________________________________________________________________
Name: svn:ignore
- Makefile
Makefile.in
test-exp-parser
test-link-module
test-print-parse-amount
test-print-queries
test-scm-query-string
.deps
.libs
semantic.cache
TAGS
*.exe
+ Makefile
Makefile.in
test-exp-parser
test-link-module
test-print-parse-amount
test-print-queries
test-scm-query-string
test-sx
.deps
.libs
semantic.cache
TAGS
*.exe
Modified: gnucash/trunk/src/app-utils/test/Makefile.am
===================================================================
--- gnucash/trunk/src/app-utils/test/Makefile.am 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/app-utils/test/Makefile.am 2007-01-19 23:45:45 UTC (rev 15399)
@@ -3,7 +3,8 @@
test-load-module \
test-exp-parser \
test-scm-query-string \
- test-print-parse-amount
+ test-print-parse-amount \
+ test-sx
test_exp_parser_SOURCES = \
${top_builddir}/src/core-utils/gnc-gconf-utils.c \
@@ -48,7 +49,8 @@
test-exp-parser \
test-print-parse-amount \
test-scm-query-string \
- test-print-queries
+ test-print-queries \
+ test-sx
EXTRA_DIST = \
test-load-module
Modified: gnucash/trunk/src/app-utils/test/test-exp-parser.c
===================================================================
--- gnucash/trunk/src/app-utils/test/test-exp-parser.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/app-utils/test/test-exp-parser.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -209,10 +209,22 @@
}
static void
+test_variable_expressions()
+{
+ gnc_numeric num;
+ gchar *errLoc = NULL;
+ GHashTable *vars = g_hash_table_new(g_str_hash, g_str_equal);
+ do_test(gnc_exp_parser_parse_separate_vars("123 + a", &num, &errLoc, vars), "parsing");
+ do_test(g_hash_table_size(vars) == 1, "'a' is the variable; good job, gnc-exp-parser!");
+ success("variable found");
+}
+
+static void
real_main (void *closure, int argc, char **argv)
{
/* set_should_print_success (TRUE); */
test_parser();
+ test_variable_expressions();
print_test_results();
exit(get_rv());
}
Copied: gnucash/trunk/src/app-utils/test/test-sx.c (from rev 15384, gnucash/branches/sx-cleanup/src/app-utils/test/test-sx.c)
Modified: gnucash/trunk/src/backend/file/io-gncxml-v2.c
===================================================================
--- gnucash/trunk/src/backend/file/io-gncxml-v2.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/backend/file/io-gncxml-v2.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -237,16 +237,19 @@
static gboolean
add_schedXaction_local(sixtp_gdv2 *data, SchedXaction *sx)
{
- GList *list;
-
- list = gnc_book_get_schedxactions (data->book);
- list = g_list_append(list, sx);
-
- gnc_book_set_schedxactions(data->book, list);
- data->counter.schedXactions_loaded++;
- run_callback(data, "schedXactions");
-
- return TRUE;
+ SchedXactions *sxes;
+#if 0 // old
+ GList *list;
+ list = gnc_book_get_schedxactions (data->book);
+ list = g_list_append(list, sx);
+ gnc_book_set_schedxactions(data->book, list);
+#endif // 0
+ sxes = gnc_book_get_schedxactions(data->book);
+ gnc_sxes_add_sx(sxes, sx);
+ data->counter.schedXactions_loaded++;
+ run_callback(data, "schedXactions");
+
+ return TRUE;
}
static gboolean
@@ -932,7 +935,7 @@
"transaction",
gnc_book_count_transactions(book),
"schedxaction",
- g_list_length( gnc_book_get_schedxactions(book) ),
+ g_list_length(gnc_book_get_schedxactions(book)->sx_list),
"budget", qof_collection_count(
qof_book_get_collection(book, GNC_ID_BUDGET)),
NULL);
@@ -1067,25 +1070,24 @@
static void
write_schedXactions( FILE *out, QofBook *book, sixtp_gdv2 *gd)
{
- GList *schedXactions;
- SchedXaction *tmpSX;
- xmlNodePtr node;
+ GList *schedXactions;
+ SchedXaction *tmpSX;
+ xmlNodePtr node;
+
+ schedXactions = gnc_book_get_schedxactions(book)->sx_list;
- /* get list of scheduled transactions from QofBook */
- schedXactions = gnc_book_get_schedxactions( book );
+ if ( schedXactions == NULL )
+ return;
- if ( schedXactions == NULL )
- return;
-
- do {
- tmpSX = schedXactions->data;
- node = gnc_schedXaction_dom_tree_create( tmpSX );
- xmlElemDump( out, NULL, node );
- fprintf( out, "\n" );
- xmlFreeNode( node );
- gd->counter.schedXactions_loaded++;
- run_callback(gd, "schedXactions");
- } while ( (schedXactions = schedXactions->next) );
+ do {
+ tmpSX = schedXactions->data;
+ node = gnc_schedXaction_dom_tree_create( tmpSX );
+ xmlElemDump( out, NULL, node );
+ fprintf( out, "\n" );
+ xmlFreeNode( node );
+ gd->counter.schedXactions_loaded++;
+ run_callback(gd, "schedXactions");
+ } while ( (schedXactions = schedXactions->next) );
}
static void
@@ -1175,7 +1177,7 @@
xaccGroupGetNumSubAccounts(gnc_book_get_group(book));
gd->counter.transactions_total = gnc_book_count_transactions(book);
gd->counter.schedXactions_total =
- g_list_length( gnc_book_get_schedxactions(book));
+ g_list_length(gnc_book_get_schedxactions(book)->sx_list);
gd->counter.budgets_total = qof_collection_count(
qof_book_get_collection(book, GNC_ID_BUDGET));
Modified: gnucash/trunk/src/core-utils/gnc-glib-utils.c
===================================================================
--- gnucash/trunk/src/core-utils/gnc-glib-utils.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/core-utils/gnc-glib-utils.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -27,7 +27,7 @@
#include "gnc-glib-utils.h"
-int
+int
safe_utf8_collate (const char * da, const char * db)
{
if (da && !(*da))
@@ -222,3 +222,31 @@
gnc_utf8_strip_invalid (result);
return result;
}
+
+GList*
+gnc_g_list_map(GList* list, GncGMapFunc fn, gpointer user_data)
+{
+ GList *rtn = NULL;
+ for (; list != NULL; list = list->next)
+ {
+ rtn = g_list_append(rtn, (*fn)(list->data, user_data));
+ }
+ return rtn;
+}
+
+void
+gnc_g_list_cut(GList **list, GList *cut_point)
+{
+ if (list == NULL || *list == NULL)
+ return;
+
+ // if it's the first element.
+ if (cut_point->prev == NULL)
+ {
+ *list = NULL;
+ return;
+ }
+
+ cut_point->prev->next = NULL;
+ cut_point->prev = NULL;
+}
Modified: gnucash/trunk/src/core-utils/gnc-glib-utils.h
===================================================================
--- gnucash/trunk/src/core-utils/gnc-glib-utils.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/core-utils/gnc-glib-utils.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -81,7 +81,20 @@
* caller. */
gchar *gnc_utf8_strip_invalid_strdup (const gchar* str);
+typedef gpointer (*GncGMapFunc)(gpointer data, gpointer user_data);
+/**
+ * @return Caller-owned GList* of results of apply `fn` to `list` in order.
+ **/
+GList* gnc_g_list_map(GList* list, GncGMapFunc fn, gpointer user_data);
+
+/**
+ * Cut a GList into two parts; the {@param cut_point} is the beginning of the
+ * new list; {@param list} may need to be modified, but will be the list
+ * before the {@param cut_point}.
+ **/
+void gnc_g_list_cut(GList **list, GList *cut_point);
+
/** @} */
#endif /* GNC_GLIB_UTILS_H */
Copied: gnucash/trunk/src/doc/sx.rst (from rev 15384, gnucash/branches/sx-cleanup/src/doc/sx.rst)
Modified: gnucash/trunk/src/engine/SX-book-p.h
===================================================================
--- gnucash/trunk/src/engine/SX-book-p.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/SX-book-p.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -35,23 +35,16 @@
#define GNC_SX_BOOK_P_H
#include "qof.h"
+#include "SX-book.h"
/* ====================================================================== */
-struct xaccSchedXactionsDef {
- GList *sx_list;
- gboolean sx_notsaved;
-};
+SchedXactions* gnc_collection_get_schedxactions(const QofCollection *col);
-void gnc_book_set_schedxactions( QofBook *book, GList *newList );
-void gnc_collection_set_schedxactions( QofCollection *col, GList *newList );
-
-
/* Associate the given template group with a book */
void gnc_book_set_template_group (QofBook *book, AccountGroup *templateGroup);
void gnc_collection_set_template_group (QofCollection *col, AccountGroup *templateGroup);
-
gboolean gnc_sxtt_register (void);
#endif /* GNC_SX_BOOK_P_H */
Modified: gnucash/trunk/src/engine/SX-book.c
===================================================================
--- gnucash/trunk/src/engine/SX-book.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/SX-book.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -44,6 +44,7 @@
#include "SchedXaction.h"
#include "SX-book.h"
#include "SX-book-p.h"
+#include "gnc-event.h"
static QofLogModule log_module = GNC_MOD_SX;
@@ -116,7 +117,6 @@
gnc_book_set_template_group (book, NULL);
}
-
static gboolean
sxtg_is_dirty(const QofCollection *col)
{
@@ -144,78 +144,45 @@
/* ====================================================================== */
-SchedXactions *
-gnc_collection_get_schedxaction_list(const QofCollection *col)
-{
- return qof_collection_get_data (col);
-}
-
-GList *
+SchedXactions*
gnc_collection_get_schedxactions(const QofCollection *col)
{
- SchedXactions *list;
- list = qof_collection_get_data (col);
- if (list) return list->sx_list;
- return NULL;
+ SchedXactions *rtn = qof_collection_get_data(col);
+ // @@assert(rtn != null);
+ return rtn;
}
-GList *
+SchedXactions*
gnc_book_get_schedxactions(QofBook *book)
{
QofCollection *col;
- col = qof_book_get_collection (book, GNC_ID_SXTT);
- return gnc_collection_get_schedxactions (col);
+ col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
+ return gnc_collection_get_schedxactions(col);
}
void
-gnc_collection_set_schedxactions( QofCollection *col, GList *newList )
+gnc_sxes_add_sx(SchedXactions *sxes, SchedXaction *sx)
{
- SchedXactions *old_list, *new_list;
- if ( col == NULL ) return;
-
- old_list = qof_collection_get_data (col);
- if (old_list && old_list->sx_list == newList)
- {
- /* Assume the worst, that any 'set' means the data has
- * changed, and needs to be saved. */
- old_list->sx_notsaved = TRUE;
- return;
- }
-
- new_list = g_new (SchedXactions, 1);
- new_list->sx_list = newList;
- new_list->sx_notsaved = TRUE;
- if (NULL == newList) new_list->sx_notsaved = FALSE;
-
- qof_collection_set_data (col, new_list);
-
- g_free (old_list);
+ if (g_list_find(sxes->sx_list, sx) != NULL)
+ return;
+ sxes->sx_list = g_list_append(sxes->sx_list, sx);
+ qof_event_gen(&sxes->inst.entity, GNC_EVENT_ITEM_ADDED, (gpointer)sx);
}
void
-gnc_book_set_schedxactions( QofBook *book, GList *newList )
+gnc_sxes_del_sx(SchedXactions *sxes, SchedXaction *sx)
{
- QofCollection *col;
- if ( book == NULL ) return;
-
- col = qof_book_get_collection (book, GNC_ID_SXTT);
- gnc_collection_set_schedxactions (col, newList);
+ GList *to_remove;
+ to_remove = g_list_find(sxes->sx_list, sx);
+ if (to_remove == NULL)
+ return;
+ sxes->sx_list = g_list_delete_link(sxes->sx_list, to_remove);
+ qof_event_gen(&sxes->inst.entity, GNC_EVENT_ITEM_REMOVED, (gpointer)sx);
}
/* ====================================================================== */
/* SX-trans stuff */
-static void
-sxtt_book_begin (QofBook *book)
-{
- gnc_book_set_schedxactions (book, NULL);
-}
-
-static void
-sxtt_book_end (QofBook *book)
-{
- gnc_book_set_schedxactions (book, NULL);
-}
static void
mark_sx_clean(gpointer data, gpointer user_data)
{
@@ -224,13 +191,28 @@
}
static void
+book_sxes_setup(QofBook *book)
+{
+ QofCollection *col;
+ SchedXactions *sxes;
+
+ col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION);
+ sxes = g_new (SchedXactions, 1);
+ qof_instance_init(&sxes->inst, GNC_ID_SXES, book);
+ sxes->sx_list = NULL;
+ sxes->sx_notsaved = TRUE;
+ qof_collection_set_data(col, sxes);
+}
+
+static void
book_sxns_mark_saved(QofCollection *col)
{
SchedXactions *sxl;
-
- sxl = gnc_collection_get_schedxaction_list (col);
- if (sxl) sxl->sx_notsaved = FALSE;
- g_list_foreach(gnc_collection_get_schedxactions(col),
+ sxl = gnc_collection_get_schedxactions(col);
+ if (!sxl)
+ return;
+ sxl->sx_notsaved = FALSE;
+ g_list_foreach(sxl->sx_list,
mark_sx_clean,
NULL);
}
@@ -241,10 +223,11 @@
GList *sxlist;
SchedXactions *sxl;
- sxl = gnc_collection_get_schedxaction_list (col);
+ sxl = gnc_collection_get_schedxactions(col);
+ if (!sxl) return FALSE;
if((sxl && sxl->sx_notsaved)) return TRUE;
- for(sxlist = gnc_collection_get_schedxactions(col);
+ for(sxlist = sxl->sx_list;
sxlist != NULL;
sxlist = g_list_next(sxlist))
{
@@ -256,6 +239,21 @@
return FALSE;
}
+
+static QofObject sxes_object_def =
+{
+ interface_version: QOF_OBJECT_VERSION,
+ e_type: GNC_ID_SXES,
+ type_label: "Scheduled Transactions List",
+ create: NULL,
+ book_begin: book_sxes_setup,
+ book_end: NULL,
+ is_dirty: book_sxlist_notsaved,
+ mark_clean: book_sxns_mark_saved,
+ foreach: NULL,
+ printable: NULL,
+ version_cmp: NULL
+};
static QofObject sxtt_object_def =
{
@@ -263,10 +261,10 @@
e_type: GNC_ID_SXTT,
type_label: "Scheduled Transaction Templates",
create: NULL,
- book_begin: sxtt_book_begin,
- book_end: sxtt_book_end,
- is_dirty: book_sxlist_notsaved,
- mark_clean: book_sxns_mark_saved,
+ book_begin: NULL,
+ book_end: NULL,
+ is_dirty: NULL,
+ mark_clean: NULL,
foreach: NULL,
printable: NULL,
version_cmp: NULL,
@@ -275,8 +273,11 @@
gboolean
gnc_sxtt_register (void)
{
- return qof_object_register (&sxtg_object_def);
- return qof_object_register (&sxtt_object_def);
+ if (!qof_object_register(&sxes_object_def))
+ return FALSE;
+ if (!qof_object_register(&sxtg_object_def))
+ return FALSE;
+ return qof_object_register(&sxtt_object_def);
}
GList*
@@ -284,7 +285,7 @@
{
GList *rtn = NULL;
const GUID *acct_guid = xaccAccountGetGUID(acct);
- GList *sx_list = gnc_book_get_schedxactions(book);
+ GList *sx_list = gnc_book_get_schedxactions(book)->sx_list;
for (; sx_list != NULL; sx_list = sx_list->next)
{
SchedXaction *sx = (SchedXaction*)sx_list->data;
Modified: gnucash/trunk/src/engine/SX-book.h
===================================================================
--- gnucash/trunk/src/engine/SX-book.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/SX-book.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -30,6 +30,7 @@
* @brief Anchor Scheduled Transaction info in a book.
* See src/doc/books.txt for design overview.
* @author Copyright (c) 2003 Linas Vepstas <linas at linas.org>
+ * @author Copyright (c) 2006 Joshua Sled <jsled at asynchronous.org>
*
* XXX currently, this is crufty, it should be modified to use
* entities a bit more whole-heartedly than it does.
@@ -39,17 +40,28 @@
#define GNC_SX_BOOK_H
#include <glib.h>
+#include "SchedXaction.h"
#include "qof.h"
typedef struct xaccSchedXactionsDef SchedXactions;
-SchedXactions * gnc_collection_get_schedxaction_list(const QofCollection *col);
-GList * gnc_collection_get_schedxactions(const QofCollection *col);
-GList * gnc_book_get_schedxactions(QofBook *book);
+struct xaccSchedXactionsDef {
+ QofInstance inst;
+ GList* sx_list;
+ gboolean sx_notsaved;
+};
+#define GNC_IS_SXES(obj) (QOF_CHECK_TYPE((obj), GNC_ID_SXES))
+#define GNC_SXES(obj) (QOF_CHECK_CAST((obj), GNC_ID_SXES, SchedXactions))
+
+SchedXactions* gnc_book_get_schedxactions(QofBook* book);
+
+void gnc_sxes_add_sx(SchedXactions* sxes, SchedXaction* sx);
+void gnc_sxes_del_sx(SchedXactions* sxes, SchedXaction* sx);
+
/** Returns the template group from the book. **/
-AccountGroup * gnc_book_get_template_group(QofBook *book);
-AccountGroup * gnc_collection_get_template_group(const QofCollection *col);
+AccountGroup* gnc_book_get_template_group(QofBook* book);
+AccountGroup* gnc_collection_get_template_group(const QofCollection *col);
/** @return The list of SXes which reference the given Account. Caller should free this list. **/
GList* gnc_sx_get_sxes_referencing_account(QofBook *book, Account *acct);
Modified: gnucash/trunk/src/engine/SchedXaction.c
===================================================================
--- gnucash/trunk/src/engine/SchedXaction.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/SchedXaction.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -192,13 +192,18 @@
PERR ("Failed to commit: %d", errcode);
}
-static void noop (QofInstance *inst) {}
+static void commit_done(QofInstance *inst)
+{
+ qof_event_gen (&inst->entity, QOF_EVENT_MODIFY, NULL);
+}
+static void noop(QofInstance *inst) {}
+
void
gnc_sx_commit_edit (SchedXaction *sx)
{
if (!qof_commit_edit (QOF_INSTANCE(sx))) return;
- qof_commit_edit_part2 (&sx->inst, commit_err, noop, noop);
+ qof_commit_edit_part2 (&sx->inst, commit_err, commit_done, noop);
}
/* ============================================================ */
@@ -375,8 +380,10 @@
gboolean *outAutoCreate,
gboolean *outNotify )
{
- *outAutoCreate = sx->autoCreateOption;
- *outNotify = sx->autoCreateNotify;
+ if (outAutoCreate != NULL)
+ *outAutoCreate = sx->autoCreateOption;
+ if (outNotify != NULL)
+ *outNotify = sx->autoCreateNotify;
return;
}
Modified: gnucash/trunk/src/engine/SchedXaction.h
===================================================================
--- gnucash/trunk/src/engine/SchedXaction.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/SchedXaction.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -42,6 +42,9 @@
#include "FreqSpec.h"
#include "gnc-engine.h"
+#define GNC_IS_SX(obj) (QOF_CHECK_TYPE((obj), GNC_ID_SCHEDXACTION))
+#define GNC_SX(obj) (QOF_CHECK_CAST((obj), GNC_ID_SCHEDXACTION, SchedXaction))
+
/**
* The SchedXaction data.
*/
@@ -196,7 +199,7 @@
This is a date-sorted state-data instance list.
The list should not be modified by the caller; use the
- gnc_sx_{add,remove}_defer_instance() functions to modifiy the list.
+ gnc_sx_{add,remove}_defer_instance() functions to modify the list.
*/
GList *gnc_sx_get_defer_instances( SchedXaction *sx );
Modified: gnucash/trunk/src/engine/gnc-engine.h
===================================================================
--- gnucash/trunk/src/engine/gnc-engine.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/gnc-engine.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -98,8 +98,9 @@
#define GNC_ID_PRICE "Price"
#define GNC_ID_PRICEDB "PriceDB"
#define GNC_ID_SPLIT "Split"
+#define GNC_ID_BUDGET "Budget"
#define GNC_ID_SCHEDXACTION "SchedXaction"
-#define GNC_ID_BUDGET "Budget"
+#define GNC_ID_SXES "SchedXactions"
#define GNC_ID_SXTG "SXTGroup"
#define GNC_ID_SXTT "SXTTrans"
#define GNC_ID_TRANS "Trans"
Modified: gnucash/trunk/src/engine/test/test-freq-spec.c
===================================================================
--- gnucash/trunk/src/engine/test/test-freq-spec.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/test/test-freq-spec.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -559,6 +559,50 @@
xaccFreqSpecFree(fs);
}
+static void
+test_monthly_31st_bug_104844()
+{
+ gchar date_buf[128];
+ GDate start, next, expected;
+ FreqSpec *fs = xaccFreqSpecMalloc(book);
+
+ g_date_clear(&next, 1);
+
+ g_date_clear(&start, 1);
+ g_date_set_dmy(&start, 31, 1, 2003);
+ xaccFreqSpecSetMonthly(fs, &start, 1);
+
+ //g_date_add_days(&start, 1);
+ xaccFreqSpecGetNextInstance(fs, &start, &next);
+ g_date_clear(&expected, 1);
+ g_date_set_dmy(&expected, 28, 2, 2003);
+ g_date_strftime(date_buf, 128, "%c", &next);
+ do_test(g_date_compare(&expected, &next) == 0, date_buf);
+
+ start = next;
+ xaccFreqSpecGetNextInstance(fs, &start, &next);
+ g_date_set_dmy(&expected, 31, 3, 2003);
+ g_date_strftime(date_buf, 128, "%c", &next);
+ do_test(g_date_compare(&expected, &next) == 0, date_buf);
+
+ // test...
+ g_date_set_dmy(&start, 31, 1, 2003);
+ xaccFreqSpecSetMonthly(fs, &start, 1);
+ g_date_set_dmy(&start, 31, 1, 2007);
+ xaccFreqSpecGetNextInstance(fs, &start, &next);
+ g_date_set_dmy(&expected, 28, 2, 2007);
+ g_date_strftime(date_buf, 128, "%c", &next);
+ do_test(g_date_compare(&expected, &next) == 0, date_buf);
+
+ start = next;
+ xaccFreqSpecGetNextInstance(fs, &start, &next);
+ g_date_set_dmy(&expected, 31, 3, 2007);
+ g_date_strftime(date_buf, 128, "%c", &next);
+ do_test(g_date_compare(&expected, &next) == 0, date_buf);
+
+ xaccFreqSpecFree(fs);
+}
+
int
main (int argc, char **argv)
{
@@ -568,6 +612,9 @@
g_return_val_if_fail(cashobjects_register(), -1);
session = qof_session_new ();
book = qof_session_get_book(session);
+
+ test_monthly_31st_bug_104844();
+
test_once();
test_caseA();
test_daily();
@@ -575,6 +622,7 @@
test_monthly();
test_month_relative();
test_composite();
+
print_test_results();
qof_session_end(session);
qof_close();
Modified: gnucash/trunk/src/engine/test/test-transaction-voiding.c
===================================================================
--- gnucash/trunk/src/engine/test/test-transaction-voiding.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/test/test-transaction-voiding.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -193,14 +193,14 @@
int
main (int argc, char **argv)
{
- qof_init();
- if(cashobjects_register())
- {
- xaccLogDisable ();
- run_test ();
- success("transaction voiding seems OK");
- print_test_results();
- }
- qof_close();
+ qof_init();
+ if(cashobjects_register())
+ {
+ xaccLogDisable ();
+ run_test ();
+ success("transaction voiding seems OK");
+ print_test_results();
+ }
+ qof_close();
return get_rv();
}
Modified: gnucash/trunk/src/engine/test-core/test-engine-stuff.c
===================================================================
--- gnucash/trunk/src/engine/test-core/test-engine-stuff.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/test-core/test-engine-stuff.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -32,8 +32,12 @@
#include "Group.h"
#include "GroupP.h"
#include "gnc-engine.h"
+#include "gnc-session.h"
#include "Transaction.h"
#include "TransactionP.h"
+#include "FreqSpec.h"
+#include "SchedXaction.h"
+#include "SX-book.h"
#include "test-engine-stuff.h"
#include "test-stuff.h"
@@ -2160,3 +2164,61 @@
return q;
}
+
+static FreqSpec*
+daily_freq(GDate* start, int multiplier)
+{
+ QofBook *book = qof_session_get_book(gnc_get_current_session());
+ FreqSpec *freq = xaccFreqSpecMalloc(book);
+ xaccFreqSpecSetDaily(freq, start, multiplier);
+ xaccFreqSpecSetUIType(freq, UIFREQ_DAILY);
+ return freq;
+}
+
+static FreqSpec*
+once_freq(GDate *when)
+{
+ QofBook *book = qof_session_get_book(gnc_get_current_session());
+ FreqSpec *freq = xaccFreqSpecMalloc(book);
+ xaccFreqSpecSetOnceDate(freq, when);
+ xaccFreqSpecSetUIType(freq, UIFREQ_ONCE);
+ return freq;
+}
+
+static SchedXaction*
+add_sx(gchar *name, GDate *start, GDate *end, GDate *last_occur, FreqSpec *fs)
+{
+ QofBook *book = qof_session_get_book(gnc_get_current_session());
+ SchedXaction *sx = xaccSchedXactionMalloc(book);
+ xaccSchedXactionSetName(sx, name);
+ xaccSchedXactionSetStartDate(sx, start);
+ if (end != NULL)
+ xaccSchedXactionSetEndDate(sx, end);
+ if (last_occur != NULL)
+ xaccSchedXactionSetLastOccurDate(sx, last_occur);
+ xaccSchedXactionSetFreqSpec(sx, fs);
+
+ gnc_sxes_add_sx(gnc_book_get_schedxactions(book), sx);
+
+ return sx;
+}
+
+SchedXaction*
+add_daily_sx(gchar *name, GDate *start, GDate *end, GDate *last_occur)
+{
+ return add_sx(name, start, end, last_occur, daily_freq(start, 1));
+}
+
+SchedXaction*
+add_once_sx(gchar *name, GDate *when)
+{
+ return add_sx(name, when, NULL, NULL, once_freq(when));
+}
+
+void
+remove_sx(SchedXaction *sx)
+{
+ QofBook *book = qof_session_get_book(gnc_get_current_session());
+ SchedXactions *sxes = gnc_book_get_schedxactions(book);
+ gnc_sxes_del_sx(sxes, sx);
+}
Modified: gnucash/trunk/src/engine/test-core/test-engine-stuff.h
===================================================================
--- gnucash/trunk/src/engine/test-core/test-engine-stuff.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/engine/test-core/test-engine-stuff.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -11,6 +11,7 @@
#include "qof.h"
#include "Query.h"
#include "gnc-pricedb.h"
+#include "SchedXaction.h"
Timespec* get_random_timespec(void);
void random_timespec_zero_nsec (gboolean zero_nsec);
@@ -88,4 +89,8 @@
void make_random_changes_to_book (QofBook *book);
void make_random_changes_to_session (QofSession *session);
+SchedXaction* add_daily_sx(gchar *name, GDate *start, GDate *end, GDate *last_occur);
+SchedXaction* add_once_sx(gchar *name, GDate *when);
+void remove_sx(SchedXaction *sx);
+
#endif
Modified: gnucash/trunk/src/gnome/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome/Makefile.am 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/Makefile.am 2007-01-19 23:45:45 UTC (rev 15399)
@@ -29,11 +29,11 @@
dialog-price-edit-db.c \
dialog-print-check.c \
dialog-progress.c \
+ dialog-sx-editor.c \
dialog-sx-from-trans.c \
- dialog-sxsincelast.c \
+ dialog-sx-since-last-run.c \
dialog-tax-info.c \
dialog-userpass.c \
- dialog-scheduledxaction.c \
druid-acct-period.c \
druid-hierarchy.c \
druid-merge.c \
@@ -45,8 +45,10 @@
gnc-plugin-register.c \
gnc-plugin-page-account-tree.c \
gnc-plugin-page-budget.c \
+ gnc-plugin-page-sx-list.c \
gnc-plugin-page-register.c \
gnc-split-reg.c \
+ gnc-sx-list-tree-model-adapter.c \
lot-viewer.c \
reconcile-list.c \
top-level.c \
@@ -67,9 +69,9 @@
dialog-new-user.h \
dialog-print-check.h \
dialog-progress.h \
+ dialog-sx-editor.h \
dialog-sx-from-trans.h \
- dialog-sxsincelast.h \
- dialog-scheduledxaction.h \
+ dialog-sx-since-last-run.h \
druid-acct-period.h \
druid-hierarchy.h \
druid-merge.h \
@@ -81,8 +83,10 @@
gnc-plugin-register.h \
gnc-plugin-page-account-tree.h \
gnc-plugin-page-budget.h \
+ gnc-plugin-page-sx-list.h \
gnc-plugin-page-register.h \
gnc-split-reg.h \
+ gnc-sx-list-tree-model-adapter.h \
lot-viewer.h \
reconcile-list.h \
top-level.h \
Deleted: gnucash/trunk/src/gnome/dialog-scheduledxaction.c
===================================================================
--- gnucash/trunk/src/gnome/dialog-scheduledxaction.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/dialog-scheduledxaction.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,2595 +0,0 @@
-/********************************************************************\
- * dialog-scheduledxaction.c : dialog for scheduled transaction *
- * list and editor *
- * Copyright (C) 2001,2002,2006 Joshua Sled <jsled at asynchronous.org>*
- * *
- * 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 *
-\********************************************************************/
-
-#include "config.h"
-
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include "glib-compat.h"
-#include <locale.h>
-#include <time.h>
-
-#include "qof.h"
-#include "gnc-book.h"
-#include "Account.h"
-#include "FreqSpec.h"
-#include "SchedXaction.h"
-#include "SX-book.h"
-#include "SX-book-p.h"
-#include "dialog-preferences.h"
-#include "dialog-scheduledxaction.h"
-#include "dialog-utils.h"
-#include "gnc-book.h"
-#include "gnc-component-manager.h"
-#include "gnc-date.h"
-#include "gnc-date-edit.h"
-#include "gnc-dense-cal.h"
-#include "gnc-embedded-window.h"
-#include "gnc-engine.h"
-#include "gnc-frequency.h"
-#include "gnc-gconf-utils.h"
-#include "gnc-gui-query.h"
-#include "gnc-hooks.h"
-#include "gnc-ledger-display.h"
-#include "gnc-plugin-page.h"
-#include "gnc-plugin-page-register.h"
-#include "gnc-ui.h"
-#include "gnc-ui-util.h"
-#include "gnucash-sheet.h"
-
-#include "gnc-split-reg.h"
-
-/* FIXME: temp until variable-related-stuff settled. */
-#include "dialog-sxsincelast.h"
-
-#ifdef HAVE_LANGINFO_D_FMT
-#include <langinfo.h>
-#endif
-
-static QofLogModule log_module = GNC_MOD_SX;
-
-static gint _sx_engine_event_handler_id = -1;
-
-#define SX_LIST_GCONF_SECTION "dialogs/scheduled_trans/transaction_list"
-#define SX_LIST_WIN_PREFIX "sx_list_win"
-#define SX_LIST_GLADE_NAME "Scheduled Transaction List"
-#define SX_LIST "sched_xact_list"
-#define SX_LIST_EDIT_BUTTON "edit_button"
-#define SX_LIST_DELETE_BUTTON "delete_button"
-#define SX_LIST_UPCOMING_BOX "upcoming_cal_hbox"
-#define SX_EDITOR_GLADE_NAME "Scheduled Transaction Editor"
-
-#define SXED_WIN_PREFIX "sx_editor_win"
-#define SXED_NAME_ENTRY "sxe_name"
-#define SXED_LAST_OCCUR_LABEL "last_occur_label"
-#define AUTOCREATE_OPT "autocreate_opt"
-#define NOTIFY_OPT "notify_opt"
-#define ADVANCE_OPT "advance_opt"
-#define ADVANCE_DAYS_SPIN "advance_days"
-#define REMIND_OPT "remind_opt"
-#define REMIND_DAYS_SPIN "remind_days"
-#define END_DATE_BOX "end_date_hbox"
-#define END_SPIN "end_spin"
-#define REMAIN_SPIN "remain_spin"
-
-#define SX_GLADE_FILE "sched-xact.glade"
-
-#define END_NEVER_OPTION 0
-#define END_DATE_OPTION 1
-#define NUM_OCCUR_OPTION 2
-
-#define NUM_LEDGER_LINES_DEFAULT 6
-
-#define EX_CAL_NUM_MONTHS 6
-#define EX_CAL_MO_PER_COL 2
-
-#define GNC_D_WIDTH 25
-#define GNC_D_BUF_WIDTH 26
-
-/** Datatypes ***********************************************************/
-
-typedef enum _EndTypeEnum {
- END_NEVER,
- END_DATE,
- END_OCCUR,
-} EndType;
-
-/* Runtime/dialog information about a particular SX. */
-typedef struct _SxRuntimeInfo
-{
- SchedXaction *sx;
- // the gnc-dense-cal mark-tag
- gint markTag;
- // which row in the GTK CList this SX is.
- gint row;
-} SxRuntimeInfo;
-
-struct _SchedXactionDialog
-{
- GtkWidget *dialog;
- GladeXML *gxml;
- GncDenseCal *gdcal;
- GHashTable *sxData;
-
- gint currentSortCol;
- GtkSortType currentSortType;
-};
-
-struct _SchedXactionEditorDialog
-{
- GladeXML *gxml;
- GtkWidget *dialog;
- SchedXactionDialog *sxd;
- SchedXaction *sx;
- /* If this is a new scheduled transaction or not. */
- int newsxP;
-
- /* The various widgets in the dialog */
- GNCLedgerDisplay *ledger;
-
- GNCFrequency *gncfreq;
- GncDenseCal *example_cal;
- GDate **cal_marks;
- gint markId;
-
- GtkEditable *nameEntry;
-
- GtkLabel *lastOccurLabel;
-
- GtkToggleButton *autocreateOpt;
- GtkToggleButton *notifyOpt;
- GtkToggleButton *advanceOpt;
- GtkSpinButton *advanceSpin;
- GtkToggleButton *remindOpt;
- GtkSpinButton *remindSpin;
-
- GtkToggleButton *optEndDate;
- GtkToggleButton *optEndNone;
- GtkToggleButton *optEndCount;
- GtkEntry *endCountSpin;
- GtkEntry *endRemainSpin;
- GNCDateEdit *endDateEntry;
-
- char *sxGUIDstr;
-
- GncEmbeddedWindow *embed_window;
- GncPluginPage *plugin_page;
-};
-
-/** Prototypes **********************************************************/
-
-static void putSchedXactionInDialog( gpointer data, gpointer user_data );
-
-static void generate_instances( SchedXaction *sx,
- GDate *end, GList **instanceList );
-
-static void schedXact_populate( SchedXactionDialog * );
-static void schedXact_editor_create_freq_sel( SchedXactionEditorDialog *sxed );
-static void schedXact_editor_create_ledger( SchedXactionEditorDialog *sxed );
-static void schedXact_editor_populate( SchedXactionEditorDialog * );
-
-static void sxd_close_handler ( gpointer user_data );
-
-static void new_button_clicked( GtkButton *b, gpointer d );
-static void edit_button_clicked( GtkButton *b, gpointer d );
-static void delete_button_clicked( GtkButton *b, gpointer d );
-static void close_button_clicked( GtkButton *b, gpointer d );
-static void gnc_sxl_record_size( SchedXactionDialog *sxd );
-static void gnc_sxd_row_click_handler( GtkCList *clist,
- gint col,
- gpointer ud );
-static void gnc_sxd_set_sort_compare( GtkCList *cl, gint col );
-static gint gnc_sxd_clist_compare_sx_name( GtkCList *cl,
- gconstpointer a,
- gconstpointer b );
-static gint gnc_sxd_clist_compare_sx_freq( GtkCList *cl,
- gconstpointer a,
- gconstpointer b );
-static gint gnc_sxd_clist_compare_sx_next_occur( GtkCList *cl,
- gconstpointer a,
- gconstpointer b );
-
-static void gnc_sxed_record_size( SchedXactionEditorDialog *sxed );
-static void gnc_sxed_get_widgets( SchedXactionEditorDialog *sxed );
-static void endgroup_rb_toggled( GtkButton *b, gpointer d );
-static void set_endgroup_toggle_states( SchedXactionEditorDialog *sxed, EndType t );
-static void advance_toggle( GtkButton *b, SchedXactionEditorDialog *sxed );
-static gboolean gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed );
-static gboolean gnc_sxed_check_changed( SchedXactionEditorDialog *sxed );
-static void free_keys_and_numerics_ea( gpointer key,
- gpointer value,
- gpointer user_data );
-static void gnc_sxed_save_sx( SchedXactionEditorDialog *sxed );
-static void gnc_sxed_freq_changed( GNCFrequency *gf, gpointer ud );
-static void sxed_excal_update_adapt( GtkObject *o, gpointer ud );
-static void gnc_sxed_update_cal( SchedXactionEditorDialog *sxed );
-
-static void gnc_sxed_reg_check_close(SchedXactionEditorDialog *sxed);
-
-static gint sxed_close_event( GtkDialog *dlg, gpointer ud );
-
-static gboolean sxed_confirmed_cancel( SchedXactionEditorDialog *sxed );
-
-static gboolean editor_component_sx_equality( gpointer find_data,
- gpointer user_data );
-
-static SxRuntimeInfo* _new_sx_runtime_info( SchedXaction *sx );
-static void _clear_runtime_info_row( gpointer key, gpointer value, gpointer user_data );
-
-
-static GtkActionEntry gnc_sxed_menu_entries [] =
-{
- { "EditAction", NULL, N_("_Edit"), NULL, NULL, NULL },
- { "TransactionAction", NULL, N_("_Transaction"), NULL, NULL, NULL },
- { "ViewAction", NULL, N_("_View"), NULL, NULL, NULL },
- { "ActionsAction", NULL, N_("_Actions"), NULL, NULL, NULL },
-};
-static guint gnc_sxed_menu_n_entries = G_N_ELEMENTS (gnc_sxed_menu_entries);
-
-/** Implementations *****************************************************/
-
-static
-void
-sxd_close_handler (gpointer user_data)
-{
- SchedXactionDialog *sxd = user_data;
- gnc_sxl_record_size(sxd);
- gtk_widget_hide(sxd->dialog);
- gtk_widget_destroy(sxd->dialog);
-}
-
-static
-void
-_clear_runtime_info_row( gpointer key, gpointer value, gpointer user_data )
-{
- SxRuntimeInfo *sxri;
- sxri = (SxRuntimeInfo*)value;
- sxri->row = -1;
-}
-
-void
-gnc_sxd_list_refresh( SchedXactionDialog *sxd )
-{
- GList *sxList;
- GtkCList *cl;
- GtkWidget *widget;
-
- widget = glade_xml_get_widget( sxd->gxml, SX_LIST_EDIT_BUTTON );
- gtk_widget_set_sensitive(widget, FALSE);
- widget = glade_xml_get_widget( sxd->gxml, SX_LIST_DELETE_BUTTON );
- gtk_widget_set_sensitive(widget, FALSE);
-
- /* Update the clist. */
- cl = GTK_CLIST( glade_xml_get_widget( sxd->gxml, SX_LIST ) );
- gtk_clist_freeze( cl );
-
- gtk_clist_clear( cl );
- // Also, flush the row-numbers from storage
- g_hash_table_foreach( sxd->sxData, _clear_runtime_info_row, NULL );
- sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
- g_list_foreach( sxList, putSchedXactionInDialog, sxd );
-
- gtk_clist_thaw( cl );
-}
-
-static
-void
-sxed_close_handler ( gpointer user_data )
-{
- SchedXactionEditorDialog *sxed = user_data;
-
- gnc_sxed_reg_check_close( sxed );
- gnc_sxed_record_size( sxed );
- gtk_widget_destroy( sxed->dialog );
- /* The data will be cleaned up in the destroy handler. */
-}
-
-static
-void
-close_button_clicked( GtkButton *b, gpointer d )
-{
- sxd_close_handler( d );
-}
-
-/**
- * @return TRUE if the user does want to cancel, FALSE if not. If TRUE is
- * returned, the register's changes have been cancelled.
- **/
-static
-gboolean
-sxed_confirmed_cancel( SchedXactionEditorDialog *sxed )
-{
- SplitRegister *reg;
-
- reg = gnc_ledger_display_get_split_register( sxed->ledger );
- /* check for changes */
- if ( gnc_sxed_check_changed( sxed ) ) {
- const char *sx_changed_msg =
- _( "This SX has changed; are you "
- "sure you want to cancel?" );
- if (!gnc_verify_dialog(sxed->dialog, FALSE, sx_changed_msg)) {
- return FALSE;
- }
- }
- /* cancel ledger changes */
- gnc_split_register_cancel_cursor_trans_changes( reg );
- return TRUE;
-}
-
-static
-void
-editor_cancel_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed )
-{
- /* close */
- gnc_close_gui_component_by_data( DIALOG_SCHEDXACTION_EDITOR_CM_CLASS,
- sxed );
-}
-
-static
-void
-editor_help_button_clicked(GtkButton *b, SchedXactionEditorDialog *sxed)
-{
- gnc_gnome_help(HF_HELP, HL_SXEDITOR);
-}
-
-static void
-set_var_to_random_value( gpointer key, gpointer value, gpointer ud )
-{
- if ( !value ) {
- value = g_new0( gnc_numeric, 1 );
- }
- *(gnc_numeric*)value =
- double_to_gnc_numeric( rand() + 2, 1,
- GNC_NUMERIC_RND_MASK
- | GNC_RND_FLOOR );
- g_hash_table_insert( ud, key, value );
-}
-
-static
-void
-free_keys_and_numerics_ea( gpointer key, gpointer val, gpointer ud )
-{
- g_assert( key );
- g_assert( val );
- g_free( (gchar*)key );
- g_free( (gnc_numeric*)val );
-}
-
-static
-void
-editor_ok_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed )
-{
- GNCBook *book;
- GList *sxList;
-
- if ( !gnc_sxed_check_consistent( sxed ) )
- return;
-
- gnc_sxed_save_sx( sxed );
-
- /* add to list */
- if ( sxed->newsxP ) {
- book = gnc_get_current_book ();
- sxList = gnc_book_get_schedxactions( book );
- sxList = g_list_append( sxList, sxed->sx );
- gnc_book_set_schedxactions( book, sxList );
- sxed->newsxP = FALSE;
- }
-
- /* update lists */
- /* We now do this by getting the list of SX Lists and updating them
- [if they exist]. Otherwise, our pointer to our SXD might not be
- valid; see Bug#103629. */
- {
- GList *listDialogs, *ldIter;
- listDialogs =
- gnc_find_gui_components( DIALOG_SCHEDXACTION_CM_CLASS,
- NULL, NULL );
- for ( ldIter = listDialogs;
- ldIter != NULL;
- ldIter = ldIter->next )
- {
- gnc_sxd_list_refresh( (SchedXactionDialog*)ldIter
- ->data );
- }
- if ( listDialogs != NULL )
- {
- g_list_free( listDialogs );
- }
- }
-
- /* cleanup */
- gnc_close_gui_component_by_data( DIALOG_SCHEDXACTION_EDITOR_CM_CLASS,
- sxed );
-}
-
-/**
- * Checks to see if the SX has been modified from it's previously-saved
- * state.
- * @return TRUE if this is a 'new' SX, or if the SX has changed from it's
- * previous configuration.
- **/
-static
-gboolean
-gnc_sxed_check_changed( SchedXactionEditorDialog *sxed )
-{
- if ( sxed->newsxP )
- return TRUE;
-
- /* name */
- {
- char *name;
-
- name = gtk_editable_get_chars( GTK_EDITABLE(sxed->nameEntry), 0, -1 );
- if ( strlen(name) == 0 ) {
- return TRUE;
-
- }
- if ( (xaccSchedXactionGetName(sxed->sx) == NULL)
- || (strcmp( xaccSchedXactionGetName(sxed->sx),
- name ) != 0) ) {
- return TRUE;
- }
- }
-
- /* end options */
- {
- /* dialog says... no end */
- if ( gtk_toggle_button_get_active( sxed->optEndNone ) ) {
- if ( xaccSchedXactionHasEndDate(sxed->sx)
- || xaccSchedXactionHasOccurDef(sxed->sx) ) {
- return TRUE;
- }
- }
-
- /* dialog says... end date */
- if ( gtk_toggle_button_get_active( sxed->optEndDate ) ) {
- GDate sxEndDate, dlgEndDate;
-
- if ( ! xaccSchedXactionHasEndDate( sxed->sx ) ) {
- return TRUE;
- }
- sxEndDate = *xaccSchedXactionGetEndDate( sxed->sx );
- g_date_set_time_t( &dlgEndDate,
- gnc_date_edit_get_date( sxed->
- endDateEntry ) );
-
- if ( g_date_compare( &sxEndDate, &dlgEndDate ) != 0 ) {
- return TRUE;
- }
- }
-
- /* dialog says... num occur */
- if ( gtk_toggle_button_get_active( sxed->optEndCount ) ) {
- gint sxNumOccur, sxNumRem, dlgNumOccur, dlgNumRem;
-
- if ( ! xaccSchedXactionGetNumOccur( sxed->sx ) ) {
- return TRUE;
- }
-
- dlgNumOccur =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endCountSpin) );
-
- dlgNumRem =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endRemainSpin) );
-
- sxNumOccur = xaccSchedXactionGetNumOccur( sxed->sx );
- sxNumRem = xaccSchedXactionGetRemOccur( sxed->sx );
-
- if ( (dlgNumOccur != sxNumOccur)
- || (dlgNumRem != sxNumRem) ) {
- return TRUE;
- }
- }
- }
-
- /* SX options [autocreate, notify, reminder, advance] */
- {
- gboolean dlgAutoCreate, dlgNotify, sxAutoCreate, sxNotify;
- gint dlgAdvance, sxAdvance;
- gint dlgRemind, sxRemind;
-
- dlgAutoCreate =
- gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxed->
- autocreateOpt) );
- dlgNotify =
- gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxed->
- notifyOpt) );
-
- xaccSchedXactionGetAutoCreate( sxed->sx, &sxAutoCreate, &sxNotify );
- if ( ! ((dlgAutoCreate == sxAutoCreate)
- && (dlgNotify == sxNotify)) ) {
- return TRUE;
- }
-
- dlgAdvance = 0;
- if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxed->advanceOpt) ) ) {
- dlgAdvance =
- gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(sxed->
- advanceSpin) );
- }
- sxAdvance = xaccSchedXactionGetAdvanceCreation( sxed->sx );
- if ( dlgAdvance != sxAdvance ) {
- return TRUE;
- }
-
- dlgRemind = 0;
- if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxed->remindOpt) ) ) {
- dlgRemind =
- gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(sxed->remindSpin) );
- }
- sxRemind = xaccSchedXactionGetAdvanceReminder( sxed->sx );
- if ( dlgRemind != sxRemind ) {
- return TRUE;
- }
- }
-
- /* FS, startdate */
- {
- FreqSpec *dlgFS, *sxFS;
- GDate dlgStartDate, sxStartDate;
- GString *dlgFSstr, *sxFSstr;
- gboolean fsStrCmpResult;
-
- dlgFS = xaccFreqSpecMalloc( gnc_get_current_book() );
- /* save gncFreq data */
- gnc_frequency_save_state( sxed->gncfreq, dlgFS, &dlgStartDate );
- dlgFSstr = g_string_sized_new( 16 );
- xaccFreqSpecGetFreqStr( dlgFS, dlgFSstr );
- /* get SX startdate/fs data */
- sxStartDate = *xaccSchedXactionGetStartDate( sxed->sx );
- sxFS = xaccSchedXactionGetFreqSpec( sxed->sx );
- sxFSstr = g_string_sized_new( 16 );
- xaccFreqSpecGetFreqStr( sxFS, sxFSstr );
- /* compare */
-
- fsStrCmpResult = /* lame version of comparison */
- (strcmp( dlgFSstr->str, sxFSstr->str) != 0);
- g_string_free( dlgFSstr, TRUE );
- g_string_free( sxFSstr, TRUE );
- xaccFreqSpecFree( dlgFS );
-
- if ( (g_date_compare(&dlgStartDate, &sxStartDate) != 0)
- || fsStrCmpResult ) {
- return TRUE;
- }
- }
-
- /* template transactions */
- {
- SplitRegister *sr =
- gnc_ledger_display_get_split_register( sxed->ledger );
-
- if ( gnc_split_register_changed( sr ) ) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-/**
- * Holds the credit- and debit-sum for a given Transaction, as used in
- * gnc_sxed_check_consistent.
- **/
-typedef struct _txnCreditDebitSums {
- gnc_numeric creditSum;
- gnc_numeric debitSum;
-} txnCreditDebitSums;
-
-static
-void
-set_sums_to_zero( gpointer key,
- gpointer val,
- gpointer ud )
-{
- txnCreditDebitSums *tcds = (txnCreditDebitSums*)val;
- tcds->creditSum = gnc_numeric_zero();
- tcds->debitSum = gnc_numeric_zero();
-}
-
-static
-void
-free_sums( gpointer key,
- gpointer val,
- gpointer ud )
-{
- txnCreditDebitSums *tcds = (txnCreditDebitSums*)val;
- g_free( tcds );
-}
-
-static
-void
-check_credit_debit_balance( gpointer key,
- gpointer val,
- gpointer ud )
-{
- txnCreditDebitSums *tcds = (txnCreditDebitSums*)val;
- gboolean *unbalanced = (gboolean*)ud;
- *unbalanced |= !(gnc_numeric_zero_p(
- gnc_numeric_sub_fixed( tcds->debitSum,
- tcds->creditSum ) ));
-#if GNC_DEBUG
-
- if ( gnc_numeric_zero_p( gnc_numeric_sub_fixed( tcds->debitSum,
- tcds->creditSum ) ) ) {
- DEBUG( "%.8x | true [%s - %s = %s]",
- (unsigned int)key,
- gnc_numeric_to_string( tcds->debitSum ),
- gnc_numeric_to_string( tcds->creditSum ),
- gnc_numeric_to_string(gnc_numeric_sub_fixed( tcds->debitSum,
- tcds->creditSum )) );
- } else {
- DEBUG( "%.8x | false [%s - %s = %s]",
- (unsigned int)key,
- gnc_numeric_to_string( tcds->debitSum ),
- gnc_numeric_to_string( tcds->creditSum ),
- gnc_numeric_to_string(gnc_numeric_sub_fixed( tcds->debitSum,
- tcds->creditSum )) );
- }
-#endif /* GNC_DEBUG */
-}
-
-/**
- * Checks to make sure that the SX is in a reasonable state to save.
- * @return true if checks out okay, false otherwise.
- **/
-static
-gboolean
-gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
-{
- gboolean multi_commodity = FALSE;
- gnc_commodity *base_cmdty = NULL;
- gint ttVarCount, splitCount;
- FreqSpec *fs;
-
- /* Do checks on validity and such, interrupting the user if
- * things aren't right.
- *
- * Features...
- * X support formulas [?!]
- * X balancing the SX if contain numeric-only formula data.
- * X agreement with create-automagically/notification controls
- * X the 'will ever be valid' check should take num-occur vals into
- * account.
- * X SX name is unique
- * X SX has a name
- * X "weekly" FS has some days set.
- * X "once" with reasonable start/end dates.
- * X This doesn't work at the time the 'weekly' one was fixed with
- * user-confirmation, below; the once SX is always valid.
- * [X more generically, creating a "not scheduled" SX is probably not
- * right... ]
- */
-
- ttVarCount = 0;
- splitCount = 0;
- {
- static const int NUM_ITERS_WITH_VARS = 5;
- static const int NUM_ITERS_NO_VARS = 1;
- int numIters, i;
- GHashTable *vars, *txns;
- GList *splitList = NULL;
- char *str;
- kvp_frame *f;
- kvp_value *v;
- Split *s;
- Transaction *t;
- gnc_numeric tmp;
- gboolean unbalanceable;
- gpointer unusedKey, unusedValue;
-
- unbalanceable = FALSE; /* innocent until proven guilty */
- vars = g_hash_table_new( g_str_hash, g_str_equal );
- txns = g_hash_table_new( g_direct_hash, g_direct_equal );
- numIters = NUM_ITERS_NO_VARS;
- /**
- * Plan:
- * . Do a first pass to get the variables.
- * . Set each variable to random values.
- * . see if we balance after that
- * . true: all good
- * . false: indicate to user, allow decision.
- */
-
- /* FIXME: This _really_ shouldn't require a modification of the
- * SX just to get the var names... */
- gnc_split_register_save ( gnc_ledger_display_get_split_register(sxed->ledger),
- FALSE );
- /* numeric-formulas-get-balanced determination */
- sxsl_get_sx_vars( sxed->sx, vars );
-
- ttVarCount = g_hash_table_size( vars );
- if ( ttVarCount != 0 ) {
- /* balance with random variable bindings some number
- * of times in an attempt to ferret out
- * un-balanceable transactions.
- *
- * NOTE: The Real Way to do this is with some
- * symbolic math to eliminate the variables. This is
- * hard, and we don't do it. This solution will
- * suffice for now, and perhaps for the lifetime of
- * the software. --jsled */
- numIters = NUM_ITERS_WITH_VARS;
- }
-
- srand(time(NULL));
- for ( i=0; i < numIters && !unbalanceable; i++ ) {
- g_hash_table_foreach( vars, set_var_to_random_value,
- (gpointer)vars );
- g_hash_table_foreach( txns, set_sums_to_zero, NULL );
- tmp = gnc_numeric_zero();
-
- splitList = xaccSchedXactionGetSplits( sxed->sx );
- splitCount += g_list_length( splitList );
-
- for ( ; splitList; splitList = splitList->next )
- {
- GUID *acct_guid;
- Account *acct;
- gnc_commodity *split_cmdty;
- txnCreditDebitSums *tcds;
-
- s = (Split*)splitList->data;
- t = xaccSplitGetParent( s );
-
- if ( !(tcds =
- (txnCreditDebitSums*)g_hash_table_lookup( txns,
- (gpointer)t )) )
- {
- tcds = g_new0( txnCreditDebitSums, 1 );
- tcds->creditSum = gnc_numeric_zero();
- tcds->debitSum = gnc_numeric_zero();
- g_hash_table_insert( txns, (gpointer)t, (gpointer)tcds );
- }
-
- f = xaccSplitGetSlots( s );
-
- /* contains the guid of the split's actual account. */
- v = kvp_frame_get_slot_path(f,
- GNC_SX_ID,
- GNC_SX_ACCOUNT,
- NULL);
- acct_guid = kvp_value_get_guid( v );
- acct = xaccAccountLookup( acct_guid, gnc_get_current_book ());
- split_cmdty = xaccAccountGetCommodity(acct);
- if (base_cmdty == NULL)
- {
- base_cmdty = split_cmdty;
- }
- multi_commodity |= !gnc_commodity_equal(split_cmdty, base_cmdty);
-
- v = kvp_frame_get_slot_path( f,
- GNC_SX_ID,
- GNC_SX_CREDIT_FORMULA,
- NULL );
- if ( v
- && (str = kvp_value_get_string(v))
- && strlen( str ) != 0 ) {
- if ( parse_vars_from_formula( str, vars, &tmp ) < 0 ) {
- GString *errStr;
-
- errStr = g_string_sized_new( 32 );
- g_string_printf( errStr,
- _( "Couldn't parse credit formula for "
- "split \"%s\"." ),
- xaccSplitGetMemo( s ) );
- gnc_error_dialog( GTK_WIDGET(sxed->dialog),
- errStr->str );
- g_string_free( errStr, TRUE );
-
- return FALSE;
- }
- tcds->creditSum =
- gnc_numeric_add( tcds->creditSum, tmp, 100,
- (GNC_DENOM_AUTO | GNC_DENOM_LCD) );
- tmp = gnc_numeric_zero();
- }
- v = kvp_frame_get_slot_path( f,
- GNC_SX_ID,
- GNC_SX_DEBIT_FORMULA,
- NULL );
- if ( v
- && (str = kvp_value_get_string(v))
- && strlen(str) != 0 ) {
- if ( parse_vars_from_formula( str, vars, &tmp ) < 0 ) {
- GString *errStr;
-
- errStr = g_string_sized_new( 32 );
- g_string_printf( errStr,
- _( "Couldn't parse debit formula for "
- "split \"%s\"." ),
- xaccSplitGetMemo( s ) );
- gnc_error_dialog( GTK_WIDGET(sxed->dialog),
- (gchar*)errStr->str );
- g_string_free( errStr, TRUE );
-
- return FALSE;
- }
- tcds->debitSum = gnc_numeric_add( tcds->debitSum, tmp, 100,
- (GNC_DENOM_AUTO | GNC_DENOM_LCD) );
- tmp = gnc_numeric_zero();
- }
- }
-
- g_hash_table_foreach( txns,
- check_credit_debit_balance,
- &unbalanceable );
- }
-
- /* Subtract out pre-defined vars */
- if ( g_hash_table_lookup_extended( vars, "i",
- &unusedKey,
- &unusedValue ) ) {
- ttVarCount -= 1;
- }
-
- g_hash_table_foreach( vars,
- free_keys_and_numerics_ea,
- NULL );
- g_hash_table_destroy( vars );
-
- g_hash_table_foreach( txns, free_sums, NULL );
- g_hash_table_destroy( txns );
-
- if ( unbalanceable
- && !gnc_verify_dialog( sxed->dialog, FALSE,
- "%s",
- _("The Scheduled Transaction Editor "
- "cannot automatically balance "
- "this transaction. "
- "Should it still be "
- "entered?") ) ) {
- return FALSE;
- }
- }
-
- /* read out data back into SchedXaction object. */
- /* FIXME: this is getting too deep; split out. */
- {
- gchar *name, *nameKey;
- gboolean nameExists, nameHasChanged;
- GList *sxList;
-
- name = gtk_editable_get_chars( GTK_EDITABLE(sxed->nameEntry), 0, -1 );
- if ( strlen(name) == 0 ) {
- const char *sx_has_no_name_msg =
- _( "Please name the Scheduled Transaction." );
- gnc_error_dialog( sxed->dialog, sx_has_no_name_msg );
- g_free( name );
- return FALSE;
-
- }
-
- nameExists = FALSE;
- nameKey = g_utf8_collate_key(name, -1);
- nameHasChanged =
- (xaccSchedXactionGetName(sxed->sx) == NULL)
- || (strcmp( xaccSchedXactionGetName(sxed->sx), name ) != 0);
- for ( sxList =
- gnc_book_get_schedxactions( gnc_get_current_book() );
- nameHasChanged && !nameExists && sxList ;
- sxList = sxList->next ) {
- char *existingName, *existingNameKey;
- existingName =
- xaccSchedXactionGetName( (SchedXaction*)sxList->
- data );
- existingNameKey = g_utf8_collate_key(existingName, -1);
- nameExists |= ( strcmp(nameKey, existingNameKey) == 0 );
- g_free( existingNameKey );
- }
- if ( nameHasChanged && nameExists ) {
- const char *sx_has_existing_name_msg =
- _( "A Scheduled Transaction with the "
- "name \"%s\" already exists. "
- "Are you sure you want to name "
- "this one the same?" );
- if ( ! gnc_verify_dialog( sxed->dialog, FALSE,
- sx_has_existing_name_msg,
- name) ) {
- g_free( nameKey );
- g_free( name );
- return FALSE;
- }
- }
- g_free( nameKey );
- g_free( name );
- }
-
- // @@fixme: similar to below, check the commodities involved, and disallow autocreation
- {
- gboolean autocreateState, notifyState;
-
- autocreateState =
- gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(sxed->autocreateOpt) );
- notifyState =
- gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(sxed->notifyOpt) );
-
- if (((ttVarCount > 0) || multi_commodity) && autocreateState) {
- gnc_warning_dialog(sxed->dialog,
- _("Scheduled Transactions with variables "
- "cannot be automatically created."));
- return FALSE;
- }
-
- /* Fix for part of Bug#121740 -- auto-create transactions are
- * only valid if there's actually a transaction to create. */
- if ( autocreateState && splitCount == 0 ) {
- gnc_warning_dialog( sxed->dialog,
- _("Scheduled Transactions without a template "
- "transaction cannot be automatically created.") );
- return FALSE;
- }
- }
-
- /* deal with time. */
- {
- GDate startDate, endDate, nextDate;
-
- if ( !gtk_toggle_button_get_active(sxed->optEndDate)
- && !gtk_toggle_button_get_active(sxed->optEndCount)
- && !gtk_toggle_button_get_active(sxed->optEndNone) ) {
- const char *sx_end_spec_msg =
- _( "Please provide a valid end selection." );
- gnc_error_dialog( sxed->dialog, sx_end_spec_msg );
- return FALSE;
- }
-
- if ( gtk_toggle_button_get_active(sxed->optEndCount)) {
- gint occur, rem;
-
- occur =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endCountSpin) );
-
- rem =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endRemainSpin) );
-
- if ( occur == 0 ) {
- const char *sx_occur_count_zero_msg =
- _( "There must be some number of occurrences." );
- gnc_error_dialog( sxed->dialog,
- sx_occur_count_zero_msg );
- return FALSE;
- }
-
- if ( rem > occur ) {
- const char *sx_occur_counts_wrong_msg =
- _( "The number of remaining occurrences "
- "(%d) is greater than the number of "
- "total occurrences (%d)." );
- gnc_error_dialog( sxed->dialog,
- sx_occur_counts_wrong_msg,
- rem, occur );
- return FALSE;
- }
-
- }
-
- g_date_clear( &endDate, 1 );
- if ( gtk_toggle_button_get_active(sxed->optEndDate) ) {
- g_date_set_time_t( &endDate,
- gnc_date_edit_get_date( sxed->
- endDateEntry ) );
- }
-
- /* Now, see if the user is attempting to create a SX that can't exist
- * [will never run]. */
-
- /* get the frequency spec data */
- fs = xaccFreqSpecMalloc( gnc_get_current_book() );
- gnc_frequency_save_state( sxed->gncfreq, fs, &startDate );
- /* Replicate just a smidgen of the code in the SX
- * ...GetNextInstance routine */
- g_date_subtract_days( &startDate, 1 );
- xaccFreqSpecGetNextInstance( fs, &startDate, &nextDate );
- xaccFreqSpecFree( fs );
-
- if ( !g_date_valid( &nextDate )
- || (g_date_valid( &endDate )
- && (g_date_compare( &nextDate, &endDate ) > 0)) ) {
- const char *invalid_sx_check_msg =
- _( "You have attempted to create a Scheduled "
- "Transaction which will never run. Do you "
- "really want to do this?" );
- if ( ! gnc_verify_dialog( sxed->dialog, FALSE,
- invalid_sx_check_msg) ) {
-
- return FALSE;
- }
- }
- }
- return TRUE;
-}
-
-/**
- * Saves the contents of the SX. This assumes that gnc_sxed_check_consistent
- * has returned true.
- **/
-static
-void
-gnc_sxed_save_sx( SchedXactionEditorDialog *sxed )
-{
- /* name */
- {
- char *name;
-
- name = gtk_editable_get_chars( sxed->nameEntry, 0, -1 );
- xaccSchedXactionSetName( sxed->sx, name );
- g_free( name );
- }
-
- /* date */
- {
- GDate gdate;
-
- if ( gtk_toggle_button_get_active(sxed->optEndDate) ) {
- /* get the end date data */
- g_date_set_time_t( &gdate,
- gnc_date_edit_get_date(
- sxed->endDateEntry ) );
- xaccSchedXactionSetEndDate( sxed->sx, &gdate );
- /* set the num occurances data */
- xaccSchedXactionSetNumOccur( sxed->sx, 0 );
- } else if ( gtk_toggle_button_get_active(sxed->optEndCount) ) {
- gint num;
-
- /* get the occurances data */
- num =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endCountSpin) );
- xaccSchedXactionSetNumOccur( sxed->sx, num );
-
- num =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endRemainSpin) );
- xaccSchedXactionSetRemOccur( sxed->sx, num );
-
- g_date_clear( &gdate, 1 );
- xaccSchedXactionSetEndDate( sxed->sx, &gdate );
- } else if ( gtk_toggle_button_get_active( sxed->optEndNone ) ) {
- xaccSchedXactionSetNumOccur( sxed->sx, 0 );
- g_date_clear( &gdate, 1 );
- xaccSchedXactionSetEndDate( sxed->sx, &gdate );
- } else {
- PERR( "No valid end specified\n" );
- }
- }
-
- /* Auto-create/notification states */
- {
- gboolean autocreateState, notifyState;
-
- autocreateState = gtk_toggle_button_get_active( sxed->autocreateOpt );
- notifyState = gtk_toggle_button_get_active( sxed->notifyOpt );
- /* "Notify" only makes sense if AutoCreate is actived;
- * enforce that here. */
- xaccSchedXactionSetAutoCreate( sxed->sx,
- autocreateState,
- (autocreateState & notifyState) );
- }
-
- /* days in advance */
- {
- int daysInAdvance;
-
- daysInAdvance = 0;
- if ( gtk_toggle_button_get_active( sxed->advanceOpt ) ) {
- daysInAdvance =
- gtk_spin_button_get_value_as_int( sxed->advanceSpin );
- }
- xaccSchedXactionSetAdvanceCreation( sxed->sx, daysInAdvance );
-
- daysInAdvance = 0;
- if ( gtk_toggle_button_get_active( sxed->remindOpt ) ) {
- daysInAdvance =
- gtk_spin_button_get_value_as_int( sxed->remindSpin );
- }
- xaccSchedXactionSetAdvanceReminder( sxed->sx, daysInAdvance );
- }
-
- /* start date and freq spec */
- {
- FreqSpec *fs;
- GDate gdate;
- GString *str;
-
- fs = xaccSchedXactionGetFreqSpec( sxed->sx );
- gnc_frequency_save_state( sxed->gncfreq, fs, &gdate );
-
- str = g_string_new( "" );
- xaccFreqSpecGetFreqStr( fs, str );
- DEBUG( "fs: %s", str->str );
-
- /* now that we have it, set the start date */
- xaccSchedXactionSetStartDate( sxed->sx, &gdate );
- }
-
-}
-
-static void
-autocreate_toggled( GtkObject *o, SchedXactionEditorDialog *sxed )
-{
- if ( !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o)) ) {
- gtk_toggle_button_set_active( sxed->notifyOpt, FALSE );
- }
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->notifyOpt),
- gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(o) ) );
-}
-
-static void
-advance_toggle( GtkButton *o, SchedXactionEditorDialog *sxed )
-{
- gchar *spinName;
- GtkWidget *spin;
-
- spinName = (gchar*)g_object_get_data( G_OBJECT(o), "whichOneAmI" );
- spin = glade_xml_get_widget( sxed->gxml, spinName );
- if ( !spin ) {
- PERR( "Error getting widget with name \"%s\"", spinName );
- return;
- }
- gtk_widget_set_sensitive( spin,
- gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(o) ) );
- /* FIXME: this doesn't do what we want... :( */
- gtk_editable_set_editable( GTK_EDITABLE(spin), TRUE );
-}
-
-/* Local destruction of dialog */
-static void
-scheduledxaction_dialog_destroy(GtkObject *object, gpointer data)
-{
- SchedXactionDialog *sxd = data;
-
- if ( !sxd ) return;
-
- gnc_unregister_gui_component_by_data
- (DIALOG_SCHEDXACTION_CM_CLASS, sxd);
-
- // FIXME: um. We should free memory and stuff, here...
- /*
- GladeXML *gxml;
- GncDenseCal *gdcal;
- GHashTable *sxData;
- */
-
- g_free( sxd );
-}
-
-/* Local destruction of dialog */
-static void
-scheduledxaction_editor_dialog_destroy(GtkObject *object, gpointer data)
-{
- int i;
- SchedXactionEditorDialog *sxed = data;
-
- if (sxed == NULL)
- return;
-
- gnc_unregister_gui_component_by_data
- (DIALOG_SCHEDXACTION_EDITOR_CM_CLASS, sxed);
-
- gnc_embedded_window_close_page(sxed->embed_window, sxed->plugin_page);
- gtk_widget_destroy(GTK_WIDGET(sxed->embed_window));
- sxed->embed_window = NULL;
- sxed->plugin_page = NULL;
- sxed->ledger = NULL;
-
- g_free (sxed->sxGUIDstr);
- sxed->sxGUIDstr = NULL;
-
- for ( i=0; i<(EX_CAL_NUM_MONTHS*31); i++ ) {
- g_free( sxed->cal_marks[i] );
- }
- g_free( sxed->cal_marks );
-
- if ( sxed->newsxP ) {
- /* FIXME: WTF???
- *
- * "WTF" explaination: in the "new" click from the caller, we
- * set this flag. When "ok" is pressed on the dialog, we set
- * this flag to false, and thus leave the SX live. If
- * "Cancel" is clicked, the flag will still be true, and this
- * SX will be cleaned, here. -- jsled
- */
- xaccSchedXactionFree( sxed->sx );
- }
- sxed->sx = NULL;
-
- g_free (sxed);
-}
-
-SchedXactionDialog*
-gnc_ui_scheduled_xaction_dialog_create(void)
-{
- SchedXactionDialog *sxd = NULL;
- GtkObject *sxdo;
- GtkWidget *button;
- GtkWidget *w;
- SchedXactionDialog *alreadyExisting = NULL;
-
- alreadyExisting =
- (SchedXactionDialog*)
- gnc_find_first_gui_component( DIALOG_SCHEDXACTION_CM_CLASS,
- NULL,
- (gpointer)sxd );
- if ( alreadyExisting != NULL ) {
- gtk_window_present( GTK_WINDOW(alreadyExisting->dialog) );
- return alreadyExisting;
- }
-
- sxd = g_new0( SchedXactionDialog, 1 );
-
- sxd->gxml = gnc_glade_xml_new( SX_GLADE_FILE, SX_LIST_GLADE_NAME );
- sxd->dialog = glade_xml_get_widget( sxd->gxml, SX_LIST_GLADE_NAME );
-
- sxd->sxData = g_hash_table_new( NULL, NULL );
-
- sxdo = GTK_OBJECT(sxd->dialog);
-
- w = glade_xml_get_widget( sxd->gxml, SX_LIST_UPCOMING_BOX );
- sxd->gdcal = GNC_DENSE_CAL( gnc_dense_cal_new() );
- gnc_dense_cal_set_months_per_col( sxd->gdcal, 4 );
- gnc_dense_cal_set_num_months( sxd->gdcal, 12 );
- gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxd->gdcal) );
-
- g_signal_connect( sxdo, "destroy",
- G_CALLBACK(scheduledxaction_dialog_destroy),
- sxd );
-
- button = glade_xml_get_widget( sxd->gxml, "new_button" );
- g_signal_connect( button, "clicked",
- G_CALLBACK(new_button_clicked), sxd );
- button = glade_xml_get_widget( sxd->gxml, "edit_button" );
- g_signal_connect( button, "clicked",
- G_CALLBACK(edit_button_clicked), sxd );
- button = glade_xml_get_widget( sxd->gxml, "delete_button" );
- g_signal_connect( button, "clicked",
- G_CALLBACK(delete_button_clicked), sxd );
- button = glade_xml_get_widget( sxd->gxml, "close_button" );
- g_signal_connect( button, "clicked",
- G_CALLBACK(close_button_clicked), sxd );
-
- w = glade_xml_get_widget( sxd->gxml, SX_LIST );
- g_signal_connect( w, "select-row",
- G_CALLBACK(row_select_handler), sxd );
- g_signal_connect( w, "unselect-row",
- G_CALLBACK(row_unselect_handler), sxd );
- g_signal_connect( w, "click-column",
- G_CALLBACK(gnc_sxd_row_click_handler), sxd );
-
- // gtk_clist_column_titles_active( GTK_CLIST( w ) );
-
- /* Default to sorting by ascending next-instance date. */
- sxd->currentSortCol = 2;
- sxd->currentSortType = GTK_SORT_ASCENDING;
- gnc_sxd_set_sort_compare( GTK_CLIST(w), sxd->currentSortCol );
- gtk_clist_set_auto_sort( GTK_CLIST(w), TRUE );
-
- gnc_restore_window_size(SX_LIST_GCONF_SECTION, GTK_WINDOW(sxd->dialog));
-
- gnc_register_gui_component( DIALOG_SCHEDXACTION_CM_CLASS,
- NULL, /* no refresh_handler */
- sxd_close_handler,
- sxd );
-
- schedXact_populate( sxd );
-
- gtk_widget_show_all(sxd->dialog);
-
- return sxd;
-}
-
-static
-void
-gnc_sxl_record_size( SchedXactionDialog *sxd )
-{
- gnc_save_window_size(SX_LIST_GCONF_SECTION, GTK_WINDOW(sxd->dialog));
-}
-
-void
-row_select_handler( GtkCList *clist,
- gint row,
- gint col,
- GdkEventButton *event,
- gpointer d )
-{
- SchedXactionDialog *sxd;
- SchedXaction *sx;
- GtkWidget *widget;
-
- sxd = (SchedXactionDialog*)d;
-
- widget = glade_xml_get_widget( sxd->gxml, SX_LIST_EDIT_BUTTON );
- gtk_widget_set_sensitive(widget, TRUE);
- widget = glade_xml_get_widget( sxd->gxml, SX_LIST_DELETE_BUTTON );
- gtk_widget_set_sensitive(widget, TRUE);
-
- if ( event == NULL ) {
- /* it could be a keypress */
- return;
- }
-
- switch ( event->type ) {
- case GDK_2BUTTON_PRESS:
- sx = (SchedXaction*)gtk_clist_get_row_data( clist, row );
- gnc_ui_scheduled_xaction_editor_dialog_create( sxd, sx, FALSE );
- break;
- default:
- /* noop */
- break;
- }
-}
-
-void
-row_unselect_handler( GtkCList *clist,
- gint row,
- gint col,
- GdkEventButton *event,
- gpointer d )
-{
- SchedXactionDialog *sxd;
- GtkWidget *widget;
-
- sxd = (SchedXactionDialog*)d;
-
- widget = glade_xml_get_widget( sxd->gxml, SX_LIST_EDIT_BUTTON );
- gtk_widget_set_sensitive(widget, FALSE);
- widget = glade_xml_get_widget( sxd->gxml, SX_LIST_DELETE_BUTTON );
- gtk_widget_set_sensitive(widget, FALSE);
-}
-
-static
-void
-schedXact_populate( SchedXactionDialog *sxd )
-{
- GList *sxList;
- GtkCList *sx_clist;
- int i;
-
- sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
- g_list_foreach( sxList, putSchedXactionInDialog, sxd );
-
- sx_clist = GTK_CLIST( glade_xml_get_widget( sxd->gxml,
- SX_LIST ) );
- for ( i=0; i<3; i++ ) {
- gtk_clist_set_column_auto_resize( sx_clist, i, TRUE );
- }
-}
-
-static
-gint
-sxed_close_event( GtkDialog *dlg, gpointer ud )
-{
- SchedXactionEditorDialog *sxed = (SchedXactionEditorDialog*)ud;
-
- /* We've already processed the SX, likely because of "ok" being
- * clicked. */
- if ( sxed->sx == NULL ) {
- return FALSE;
- }
-
- if ( ! sxed_confirmed_cancel( sxed ) ) {
- return TRUE;
- }
- return FALSE;
-}
-
-static
-void
-gnc_sxed_get_widgets( SchedXactionEditorDialog *sxed )
-{
- GtkWidget *w;
-
- w = glade_xml_get_widget( sxed->gxml, SXED_NAME_ENTRY );
- sxed->nameEntry = GTK_EDITABLE(w);
- w = glade_xml_get_widget( sxed->gxml, SXED_LAST_OCCUR_LABEL );
- sxed->lastOccurLabel = GTK_LABEL(w);
- w = glade_xml_get_widget( sxed->gxml, AUTOCREATE_OPT );
- sxed->autocreateOpt = GTK_TOGGLE_BUTTON(w);
- w = glade_xml_get_widget( sxed->gxml, NOTIFY_OPT );
- sxed->notifyOpt = GTK_TOGGLE_BUTTON(w);
- w = glade_xml_get_widget( sxed->gxml, ADVANCE_OPT );
- sxed->advanceOpt = GTK_TOGGLE_BUTTON(w);
- w = glade_xml_get_widget( sxed->gxml, ADVANCE_DAYS_SPIN );
- sxed->advanceSpin = GTK_SPIN_BUTTON(w);
- w = glade_xml_get_widget( sxed->gxml, REMIND_OPT );
- sxed->remindOpt = GTK_TOGGLE_BUTTON(w);
- w = glade_xml_get_widget( sxed->gxml, REMIND_DAYS_SPIN );
- sxed->remindSpin = GTK_SPIN_BUTTON(w);
-
- w = glade_xml_get_widget( sxed->gxml, "rb_enddate" );
- sxed->optEndDate = GTK_TOGGLE_BUTTON(w);
-
- w = glade_xml_get_widget( sxed->gxml, "rb_noend" );
- sxed->optEndNone = GTK_TOGGLE_BUTTON(w);
-
- w = glade_xml_get_widget( sxed->gxml, "rb_num_occur" );
- sxed->optEndCount = GTK_TOGGLE_BUTTON(w);
-
- w = glade_xml_get_widget( sxed->gxml, END_SPIN );
- sxed->endCountSpin = GTK_ENTRY(w);
-
- w = glade_xml_get_widget( sxed->gxml, REMAIN_SPIN );
- sxed->endRemainSpin = GTK_ENTRY(w);
-
-}
-
-SchedXactionEditorDialog *
-gnc_ui_scheduled_xaction_editor_dialog_create( SchedXactionDialog *sxd,
- SchedXaction *sx,
- gboolean newSX )
-{
- SchedXactionEditorDialog *sxed;
- GtkWidget *button;
- int i;
- GList *dlgExists = NULL;
-
- static struct widgetSignalCallback {
- char *name;
- char *signal;
- void (*fn)();
- gpointer objectData;
- } widgets[] = {
- { "ok_button", "clicked", editor_ok_button_clicked, NULL },
- { "cancel_button", "clicked", editor_cancel_button_clicked, NULL },
- { "help_button", "clicked", editor_help_button_clicked, NULL },
-
- { "rb_noend", "toggled", endgroup_rb_toggled, GINT_TO_POINTER(END_NEVER_OPTION) },
- { "rb_enddate", "toggled", endgroup_rb_toggled, GINT_TO_POINTER(END_DATE_OPTION) },
- { "rb_num_occur", "toggled", endgroup_rb_toggled, GINT_TO_POINTER(NUM_OCCUR_OPTION) },
-
- { REMAIN_SPIN , "value-changed", sxed_excal_update_adapt, NULL },
-
- { AUTOCREATE_OPT, "toggled", autocreate_toggled, NULL },
- { ADVANCE_OPT, "toggled", advance_toggle, (gpointer)ADVANCE_DAYS_SPIN },
- { REMIND_OPT, "toggled", advance_toggle, (gpointer)REMIND_DAYS_SPIN },
-
- { NULL, NULL, NULL, NULL }
- };
-
- dlgExists = gnc_find_gui_components( DIALOG_SCHEDXACTION_EDITOR_CM_CLASS,
- editor_component_sx_equality,
- sx );
- if ( dlgExists != NULL ) {
- DEBUG( "dialog already exists; using that one." );
- sxed = (SchedXactionEditorDialog*)dlgExists->data;
- gtk_window_present( GTK_WINDOW(sxed->dialog) );
- g_list_free( dlgExists );
- return sxed;
- }
-
- sxed = g_new0( SchedXactionEditorDialog, 1 );
- sxed->gxml = gnc_glade_xml_new( SX_GLADE_FILE,
- SX_EDITOR_GLADE_NAME );
- sxed->dialog = glade_xml_get_widget( sxed->gxml, SX_EDITOR_GLADE_NAME );
-
- sxed->sxd = sxd;
- sxed->sx = sx;
- sxed->newsxP = newSX;
- /* Setup dense-cal local mark storage */
- {
- sxed->cal_marks = g_new0( GDate*, EX_CAL_NUM_MONTHS * 31 );
- for( i=0; i<(EX_CAL_NUM_MONTHS * 31); i++ ) {
- sxed->cal_marks[i] = g_date_new();
- }
- sxed->markId = -1;
- }
-
- /* Setup the end-date GNC widget */
- {
- GtkWidget *endDateBox =
- glade_xml_get_widget( sxed->gxml, END_DATE_BOX );
- sxed->endDateEntry =
- GNC_DATE_EDIT(gnc_date_edit_new( time(NULL),
- FALSE, FALSE ));
- gtk_widget_show(GTK_WIDGET(sxed->endDateEntry));
- g_signal_connect( sxed->endDateEntry,
- "date-changed",
- G_CALLBACK( sxed_excal_update_adapt ),
- sxed );
- gtk_box_pack_start( GTK_BOX(endDateBox),
- GTK_WIDGET(sxed->endDateEntry),
- TRUE, TRUE, 0 );
- }
-
- /* NOTE: this must occur before processing the widget list, defined
- * above, so the gpointers stored with the advance_ and remind_opts
- * are correct. */
- gnc_sxed_get_widgets( sxed );
-
- gnc_register_gui_component( DIALOG_SCHEDXACTION_EDITOR_CM_CLASS,
- NULL, /* no refresh handler */
- sxed_close_handler,
- sxed );
-
- g_signal_connect( sxed->dialog, "close",
- G_CALLBACK(sxed_close_event), sxed );
- g_signal_connect( sxed->dialog, "destroy",
- G_CALLBACK(scheduledxaction_editor_dialog_destroy),
- sxed );
-
- for ( i=0; widgets[i].name != NULL; i++ ) {
- button = glade_xml_get_widget( sxed->gxml, widgets[i].name );
- if ( widgets[i].objectData != NULL ) {
- g_object_set_data( G_OBJECT(button), "whichOneAmI",
- widgets[i].objectData );
- }
- g_signal_connect( button, widgets[i].signal,
- G_CALLBACK( widgets[i].fn ), sxed );
- }
-
- /* For some reason the Glade-specified sensitivity settings are not
- * being honored... ? */
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->notifyOpt), FALSE );
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->advanceSpin), FALSE );
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->remindSpin), FALSE );
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->endCountSpin), FALSE );
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->endRemainSpin), FALSE );
-
- gtk_editable_set_editable( GTK_EDITABLE(sxed->advanceSpin), TRUE );
- gtk_editable_set_editable( GTK_EDITABLE(sxed->remindSpin), TRUE );
-
- /* Allow resize */
- gtk_window_set_resizable (GTK_WINDOW(sxed->dialog), TRUE);
-
- gnc_restore_window_size(SXED_GCONF_SECTION, GTK_WINDOW(sxed->dialog));
-
- /* create the frequency-selection macrowidget and example
- * [dense-]calendar. */
- schedXact_editor_create_freq_sel( sxed );
- /* create the template-transaction ledger window */
- schedXact_editor_create_ledger( sxed );
- /* populate */
- schedXact_editor_populate( sxed );
-
- /* Do not call show_all here. Screws up the gtkuimanager code */
- gtk_widget_show(sxed->dialog);
-
- /* Refresh the cal and the ledger */
- gtk_widget_queue_resize( GTK_WIDGET( sxed->example_cal ) );
- gnc_ledger_display_refresh( sxed->ledger );
-
- return sxed;
-}
-
-static
-void
-gnc_sxed_record_size( SchedXactionEditorDialog *sxed )
-{
- gnc_save_window_size( SXED_GCONF_SECTION, GTK_WINDOW(sxed->dialog) );
-}
-
-static
-void
-schedXact_editor_create_freq_sel( SchedXactionEditorDialog *sxed )
-{
- GtkBox *b;
-
- b = GTK_BOX(glade_xml_get_widget( sxed->gxml, "gncfreq_hbox" ));
- sxed->gncfreq =
- GNC_FREQUENCY( gnc_frequency_new( xaccSchedXactionGetFreqSpec(sxed->sx),
- xaccSchedXactionGetStartDate(sxed->sx) ) );
- g_assert( sxed->gncfreq );
- g_signal_connect( sxed->gncfreq, "changed",
- G_CALLBACK(gnc_sxed_freq_changed),
- sxed );
- gtk_container_add( GTK_CONTAINER(b), GTK_WIDGET(sxed->gncfreq) );
-
- b = GTK_BOX(glade_xml_get_widget( sxed->gxml, "example_cal_hbox" ));
- sxed->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new());
- g_assert( sxed->example_cal );
- gnc_dense_cal_set_num_months( sxed->example_cal, EX_CAL_NUM_MONTHS );
- gnc_dense_cal_set_months_per_col( sxed->example_cal, EX_CAL_MO_PER_COL );
- gtk_container_add( GTK_CONTAINER(b), GTK_WIDGET(sxed->example_cal) );
- gtk_widget_show( GTK_WIDGET(sxed->example_cal) );
-}
-
-static
-void
-schedXact_editor_create_ledger( SchedXactionEditorDialog *sxed )
-{
- SplitRegister *splitreg;
- GtkWidget *main_vbox;
-
- /* Create the ledger */
- /* THREAD-UNSAFE */
- sxed->sxGUIDstr = g_strdup( guid_to_string(
- xaccSchedXactionGetGUID(sxed->sx) ) );
- sxed->ledger = gnc_ledger_display_template_gl( sxed->sxGUIDstr );
- splitreg = gnc_ledger_display_get_split_register( sxed->ledger );
-
- /* First the embedded window */
- main_vbox = glade_xml_get_widget( sxed->gxml, "register_vbox" );
- sxed->embed_window =
- gnc_embedded_window_new("SXWindowActions",
- gnc_sxed_menu_entries,
- gnc_sxed_menu_n_entries,
- "gnc-sxed-window-ui.xml",
- sxed->dialog,
- FALSE, /* no accelerators */
- sxed);
- gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET(sxed->embed_window),
- TRUE, TRUE, 0);
-
- /* Now create the register plugin page. */
- sxed->plugin_page = gnc_plugin_page_register_new_ledger (sxed->ledger);
- gnc_plugin_page_set_ui_description (sxed->plugin_page,
- "gnc-sxed-window-ui-full.xml");
- gnc_plugin_page_register_set_options (sxed->plugin_page,
- NULL, NULL,
- NUM_LEDGER_LINES_DEFAULT, FALSE );
- gnc_embedded_window_open_page (sxed->embed_window, sxed->plugin_page);
-
- /* configure... */
- /* don't use double-line */
- gnc_split_register_config(splitreg,
- splitreg->type, splitreg->style,
- FALSE);
- gnc_split_register_set_auto_complete(splitreg, FALSE);
-
- /* don't show present/future divider [by definition, not necessary] */
- gnc_split_register_show_present_divider( splitreg, FALSE );
-}
-
-static
-void
-schedXact_editor_populate( SchedXactionEditorDialog *sxed )
-{
- char *name;
- time_t tmpDate;
- SplitRegister *splitReg;
- struct tm *tmpTm;
- GDate *gd;
- gint daysInAdvance;
- gboolean autoCreateState, notifyState;
-
- name = xaccSchedXactionGetName(sxed->sx);
- if ( name != NULL ) {
- gtk_entry_set_text( GTK_ENTRY(sxed->nameEntry), name );
- }
- {
- gd = xaccSchedXactionGetLastOccurDate( sxed->sx );
- if ( g_date_valid( gd ) ) {
- gchar dateBuf[ MAX_DATE_LENGTH+1 ];
- qof_print_gdate( dateBuf,MAX_DATE_LENGTH, gd );
- gtk_label_set_text( sxed->lastOccurLabel, dateBuf );
- } else {
- gtk_label_set_text( sxed->lastOccurLabel, _( "(never)" ) );
- }
- gd = NULL;
- }
-
- gd = xaccSchedXactionGetEndDate( sxed->sx );
- if ( g_date_valid( gd ) ) {
- gtk_toggle_button_set_active( sxed->optEndDate, TRUE );
- /* fill in date data. */
- tmpTm = g_new0( struct tm, 1 );
- g_date_to_struct_tm( gd, tmpTm );
- tmpDate = mktime( tmpTm );
- g_free( tmpTm );
- gnc_date_edit_set_time( sxed->endDateEntry, tmpDate );
-
- set_endgroup_toggle_states( sxed, END_DATE );
- } else if ( xaccSchedXactionHasOccurDef( sxed->sx ) ) {
- gint numOccur = xaccSchedXactionGetNumOccur( sxed->sx );
- gint numRemain = xaccSchedXactionGetRemOccur( sxed->sx );
-
- gtk_toggle_button_set_active( sxed->optEndCount, TRUE );
-
- gtk_spin_button_set_value ( GTK_SPIN_BUTTON(sxed->endCountSpin), numOccur );
- gtk_spin_button_set_value ( GTK_SPIN_BUTTON(sxed->endRemainSpin), numRemain );
-
- set_endgroup_toggle_states( sxed, END_OCCUR );
- } else {
- gtk_toggle_button_set_active( sxed->optEndNone, TRUE );
- set_endgroup_toggle_states( sxed, END_NEVER );
- }
-
- /* Do auto-create/notify setup */
- if ( sxed->newsxP ) {
- autoCreateState =
- gnc_gconf_get_bool( SXED_GCONF_SECTION, KEY_CREATE_AUTO, NULL );
- notifyState =
- gnc_gconf_get_bool( SXED_GCONF_SECTION, KEY_NOTIFY, NULL );
- } else {
- xaccSchedXactionGetAutoCreate( sxed->sx,
- &autoCreateState,
- ¬ifyState );
- }
- gtk_toggle_button_set_active( sxed->autocreateOpt, autoCreateState );
- if ( ! autoCreateState ) {
- notifyState = FALSE;
- }
- gtk_toggle_button_set_active( sxed->notifyOpt, notifyState );
-
-
- /* Do days-in-advance-to-create widget[s] setup. */
- if ( sxed->newsxP ) {
- daysInAdvance =
- gnc_gconf_get_float( SXED_GCONF_SECTION, KEY_CREATE_DAYS, NULL );
- } else {
- daysInAdvance =
- xaccSchedXactionGetAdvanceCreation( sxed->sx );
- }
- if ( daysInAdvance != 0 ) {
- gtk_toggle_button_set_active( sxed->advanceOpt, TRUE );
- gtk_spin_button_set_value( sxed->advanceSpin,
- (gfloat)daysInAdvance );
- }
-
- /* Do days-in-advance-to-remind widget[s] setup. */
- if ( sxed->newsxP ) {
- daysInAdvance =
- gnc_gconf_get_float( SXED_GCONF_SECTION, KEY_REMIND_DAYS, NULL );
- } else {
- daysInAdvance =
- xaccSchedXactionGetAdvanceReminder( sxed->sx );
- }
- if ( daysInAdvance != 0 ) {
- gtk_toggle_button_set_active( sxed->remindOpt, TRUE );
- gtk_spin_button_set_value( sxed->remindSpin,
- (gfloat)daysInAdvance );
- }
-
- if ( sxed->newsxP ) {
- gnc_sx_set_instance_count( sxed->sx, 1 );
- }
-
- /* populate the ledger */
- {
- /* create the split list */
- GList *splitList;
-
- splitList = xaccSchedXactionGetSplits( sxed->sx );
- if ( splitList != NULL ) {
- splitReg = gnc_ledger_display_get_split_register
- ( sxed->ledger );
- gnc_split_register_load(splitReg, splitList, NULL );
- } /* otherwise, use the existing stuff. */
- }
-
- /* Update the example cal */
- gnc_sxed_update_cal( sxed );
-}
-
-static
-void
-set_endgroup_toggle_states( SchedXactionEditorDialog *sxed, EndType type )
-{
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->endDateEntry), (type == END_DATE) );
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->endCountSpin), (type == END_OCCUR) );
- gtk_widget_set_sensitive( GTK_WIDGET(sxed->endRemainSpin), (type == END_OCCUR) );
-}
-
-static
-void
-new_button_clicked( GtkButton *b, gpointer d )
-{
- SchedXactionDialog *sxd;
- FreqSpec *fs;
- GDate *gd;
- SchedXaction *tmpSX =
- xaccSchedXactionMalloc( gnc_get_current_book ());
- SchedXactionEditorDialog *sxed;
-
- /* Give decent initial FreqSpec for SX */
- fs = xaccSchedXactionGetFreqSpec( tmpSX );
- gd = g_date_new();
- g_date_set_time_t( gd, time(NULL) );
- xaccFreqSpecSetMonthly( fs, gd, 1 );
- xaccFreqSpecSetUIType ( fs, UIFREQ_MONTHLY );
- g_date_free( gd );
-
- sxd = (SchedXactionDialog*)d;
- sxed = gnc_ui_scheduled_xaction_editor_dialog_create( sxd, tmpSX,
- TRUE /* newSX */ );
-}
-
-static
-void
-edit_button_clicked( GtkButton *b, gpointer d )
-{
- GList *sel;
- GtkCList *cl;
- int row;
- SchedXactionDialog *sxd;
- SchedXaction *sx;
- SchedXactionEditorDialog *sxed;
-
- sxd = (SchedXactionDialog*)d;
- cl = GTK_CLIST(glade_xml_get_widget( sxd->gxml, SX_LIST ));
- for( sel = cl->selection; sel; sel = g_list_next(sel) ) {
- row = GPOINTER_TO_INT(sel->data);
- /* get the clist row for this listitem */
- sx = (SchedXaction*)gtk_clist_get_row_data( cl, row );
- /* get the object UD */
- sxed = gnc_ui_scheduled_xaction_editor_dialog_create( sxd, sx, FALSE );
- }
-}
-
-static void
-delete_button_clicked( GtkButton *b, gpointer d )
-{
- GNCBook *book;
- GtkCList *cl;
- GList *sel, *sxList, *beingEditedList, *l;
- SchedXactionDialog *sxd;
- char *beingEditedMessage =
- _( "The following transactions are presently being edited; "
- "are you sure you want to delete them?" );
- char *confirmMessage =
- _( "Delete the selected Scheduled Transactions?" );
- GString *realConfDelOpenMsg, *realConfDeleteMsg;
- SchedXaction *sx;
- gboolean destroyOpenedResult = FALSE;
-
- sxd = (SchedXactionDialog*)d;
-
- cl = GTK_CLIST(glade_xml_get_widget( sxd->gxml, SX_LIST ));
- sel = cl->selection;
-
- if ( !sel ) {
- return;
- }
-
- realConfDeleteMsg = g_string_new( confirmMessage );
- realConfDelOpenMsg = g_string_new( beingEditedMessage );
- beingEditedList = NULL;
- for ( ; sel ; sel = sel->next ) {
- sx = (SchedXaction*)gtk_clist_get_row_data( cl, GPOINTER_TO_INT(sel->data));
- g_string_append_printf( realConfDeleteMsg, "\n\"%s\"",
- xaccSchedXactionGetName( sx ) );
- if ( (l = gnc_find_gui_components( DIALOG_SCHEDXACTION_EDITOR_CM_CLASS,
- editor_component_sx_equality,
- sx )) ) {
- beingEditedList = g_list_append( beingEditedList, (gpointer)l );
- g_string_append_printf( realConfDelOpenMsg, "\n\"%s\"",
- xaccSchedXactionGetName( sx ) );
- }
- }
-
- if ( g_list_length( beingEditedList ) > 0 ) {
- /* Figure out the user's disposition [toward the opened
- * transactions], but if it's true, don't act on it until
- * they confirm they actually want to do the deletion
- * generically. If it's false, cleanup and return. */
- if ( ! (destroyOpenedResult =
- gnc_verify_dialog( sxd->dialog, FALSE, "%s",
- realConfDelOpenMsg->str )) ) {
- for ( l = beingEditedList; l; l = l->next ) {
- g_list_free( (GList*)l->data );
- }
- g_list_free( beingEditedList );
- goto cleanupStrings;
- return; /* unreachable, but clearer. */
- }
- }
-
- if ( gnc_verify_dialog( sxd->dialog, FALSE, "%s",
- realConfDeleteMsg->str ) ) {
- /* Close the being-edited transactions. */
- if ( destroyOpenedResult ) {
- GList *component;
- for ( l = beingEditedList; l; l = l->next ) {
- SplitRegister *reg;
- component = (GList*)l->data;
- /* We'd like to force the cancellation of
- * ledger/other changes, here. */
- reg = gnc_ledger_display_get_split_register(
- ((SchedXactionEditorDialog*)component
- ->data)
- ->ledger );
- gnc_split_register_cancel_cursor_trans_changes(
- reg );
- editor_cancel_button_clicked(
- NULL,
- (SchedXactionEditorDialog*)component
- ->data );
- g_list_free( component );
- }
- g_list_free( beingEditedList );
- }
-
- /* Now, actually do the deletions... */
- book = gnc_get_current_book ();
- sxList = gnc_book_get_schedxactions( book );
- for ( sel = cl->selection; sel; sel = sel->next ) {
- SxRuntimeInfo *sxri;
- SxRuntimeInfo **p_sxri = &sxri;
- gpointer unused;
- gboolean foundP;
-
- sx = (SchedXaction*)gtk_clist_get_row_data( cl, GPOINTER_TO_INT(sel->data));
- sxList = g_list_remove( sxList, (gpointer)sx );
- gnc_book_set_schedxactions( book, sxList );
-
- foundP = g_hash_table_lookup_extended( sxd->sxData, sx,
- &unused,
- (gpointer*)p_sxri );
- g_assert( foundP );
- if ( sxri->markTag != -1 ) {
- gnc_dense_cal_mark_remove( sxd->gdcal, sxri->markTag );
- }
- g_hash_table_remove( sxd->sxData, sx );
- xaccSchedXactionFree( sx );
- }
-
- gtk_clist_freeze( cl );
- /* Remove the selected and deleted rows from the clist in
- * reverse order so each index is valid. */
- sel = g_list_copy( cl->selection );
- sel = g_list_reverse( sel );
- gtk_clist_unselect_all( cl );
- for ( ; sel; sel = sel->next ) {
- gtk_clist_remove( cl, GPOINTER_TO_INT(sel->data) );
- }
- g_list_free( sel );
- sel = NULL;
- gtk_clist_thaw( cl );
- }
-
- cleanupStrings:
- g_string_free( realConfDeleteMsg, TRUE );
- g_string_free( realConfDelOpenMsg, TRUE );
-}
-
-static
-void
-endgroup_rb_toggled( GtkButton *b, gpointer d )
-{
- /* figure out which one */
- SchedXactionEditorDialog *sxed;
- gint id;
-
- sxed = (SchedXactionEditorDialog*)d;
- id = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(b), "whichOneAmI" ));
-
- switch (id) {
- case END_NEVER_OPTION:
- set_endgroup_toggle_states( sxed, END_NEVER );
- break;
- case END_DATE_OPTION:
- set_endgroup_toggle_states( sxed, END_DATE );
- break;
- case NUM_OCCUR_OPTION:
- set_endgroup_toggle_states( sxed, END_OCCUR );
- break;
- default:
- g_error( "Unknown id %d", id );
- break;
- }
-
- gnc_sxed_update_cal( sxed );
-}
-
-/**
- * This is a copy of more complex code from dialog-sxsincelast.c. They
- * should probably be combined into a single useful function somewhere.
- **/
-static
-void
-generate_instances( SchedXaction *sx,
- GDate *end, GList **instanceList )
-{
- GDate gd, *gdToReturn;
- void *seqStateData;
-
- /* Process valid next instances */
- seqStateData = gnc_sx_create_temporal_state( sx );
- gd = xaccSchedXactionGetNextInstance( sx, seqStateData );
- while ( g_date_valid(&gd)
- && g_date_compare( &gd, end ) <= 0 ) {
-
- gdToReturn = g_date_new();
- *gdToReturn = gd;
- *instanceList = g_list_append( *instanceList, gdToReturn );
-
- gnc_sx_incr_temporal_state( sx, seqStateData );
- gd = xaccSchedXactionGetInstanceAfter( sx, &gd, seqStateData );
- }
- gnc_sx_destroy_temporal_state( seqStateData );
- seqStateData = NULL;
-}
-
-static
-void
-_gnc_sxd_free_dates( gpointer data, gpointer user_data )
-{
- g_date_free( (GDate*)data );
-}
-
-static
-SxRuntimeInfo*
-_new_sx_runtime_info( SchedXaction *sx )
-{
- SxRuntimeInfo *sxri;
-
- sxri = g_new0( SxRuntimeInfo, 1 );
- sxri->sx = sx;
- sxri->row = -1;
- sxri->markTag = -1;
- return sxri;
-}
-
-static
-void
-putSchedXactionInDialog( gpointer data, gpointer user_data )
-{
- SchedXaction *sx;
- SchedXactionDialog *sxd;
- GtkCList *clist;
- char *text[3];
- GString *freqStr;
- GString *nextDate;
- int i;
- GDate *nextInstDate = NULL, *calEndDate;
- int instArraySize;
- GDate **instArray;
- GList *instList;
- gpointer unused;
- SxRuntimeInfo *sxri = NULL;
- SxRuntimeInfo **p_sxri = &sxri;
- gboolean foundP;
- gint gdcMarkTag;
- gint row;
-
- sx = (SchedXaction*)data;
- sxd = (SchedXactionDialog*)user_data;
-
- freqStr = g_string_new( "" );
- nextDate = g_string_new( "" );
-
- xaccFreqSpecGetFreqStr( xaccSchedXactionGetFreqSpec(sx), freqStr );
-
- calEndDate = g_date_new_dmy( 1,
- gnc_dense_cal_get_month(sxd->gdcal),
- gnc_dense_cal_get_year(sxd->gdcal) );
- g_date_add_months( calEndDate,
- gnc_dense_cal_get_num_months(sxd->gdcal) );
-
- instList = NULL;
- generate_instances( sx, calEndDate, &instList );
- g_date_free( calEndDate );
-
- if ( instList == NULL ) {
- /* This was a bug [#90326]; while we do want to generate
- * instances within the visible calendar range, we also want
- * to generate the first, next SX instance regardless of the
- * calendar range. Thus, if the generate_instances above
- * returns nothing, double-check with the SX. */
- nextInstDate = g_date_new();
- *nextInstDate = xaccSchedXactionGetNextInstance( sx, NULL );
- if ( g_date_valid( nextInstDate ) ) {
- instList = g_list_append( instList,
- (gpointer)nextInstDate );
- }
- }
-
- if ( instList == NULL ) {
- g_string_printf( nextDate, _("Not scheduled") );
- } else {
- char tmpBuf[ MAX_DATE_LENGTH+1 ];
- char dowBuf[ 25 ]; /* <- FIXME: appropriate length? */
- nextInstDate = (GDate*)instList->data;
- qof_print_gdate( tmpBuf, MAX_DATE_LENGTH, nextInstDate );
- g_date_strftime( dowBuf, 25, "%A", nextInstDate );
- g_string_printf( nextDate, "%s (%s)", tmpBuf, dowBuf );
- }
-
- /* Add markings to GncDenseCal */
- gdcMarkTag = -1;
- if ( instList != NULL ) {
- GList *l;
- FreqSpec *fs;
- GString *freqDesc;
-
- instArraySize = g_list_length( instList );
- instArray = g_new0( GDate*, instArraySize );
- for ( i=0, l=instList; l; l = l->next ) {
- instArray[i++] = (GDate*)l->data;
- }
- freqDesc = g_string_sized_new(64);
- fs = xaccSchedXactionGetFreqSpec(sx);
- xaccFreqSpecGetFreqStr(fs, freqDesc );
- gdcMarkTag = gnc_dense_cal_mark( sxd->gdcal,
- instArraySize, instArray,
- xaccSchedXactionGetName(sx),
- freqDesc->str );
- g_string_free( freqDesc, TRUE );
- g_free( instArray );
- g_list_foreach( instList, _gnc_sxd_free_dates, NULL );
- g_list_free( instList );
- nextInstDate = NULL;
- }
-
- foundP = g_hash_table_lookup_extended( sxd->sxData,
- (gpointer)sx,
- &unused,
- (gpointer*)p_sxri );
- if ( ! foundP )
- {
- // new SX -- create runtime storage for it
- sxri = _new_sx_runtime_info( sx );
- sxri->markTag = gdcMarkTag;
- }
- else
- {
- // existing SX; remove it's
- if ( sxri->markTag != -1 ) {
- gnc_dense_cal_mark_remove( sxd->gdcal, sxri->markTag );
- sxri->markTag = gdcMarkTag;
- }
- }
-
-
- text[0] = xaccSchedXactionGetName( sx );
- text[1] = freqStr->str;
- text[2] = nextDate->str;
-
- clist = GTK_CLIST( glade_xml_get_widget( sxd->gxml, SX_LIST ) );
- gtk_clist_freeze( clist );
-
- row = gtk_clist_find_row_from_data( clist, (gpointer)sx );
- if ( sxri->row == -1 ) {
- /* new item to be inserted */
- sxri->row = gtk_clist_append( clist, text );
- gtk_clist_set_row_data( clist, sxri->row, sx );
- } else {
- for ( i=0; i<3; i++ ) {
- gtk_clist_set_text( clist, sxri->row, i, text[i] );
- }
- }
- gtk_clist_sort( clist );
- gtk_clist_thaw( clist );
- g_hash_table_insert( sxd->sxData, (gpointer)sx, (gpointer)sxri );
- sxri = NULL;
-
- g_string_free( freqStr, TRUE );
- g_string_free( nextDate, TRUE );
-}
-
-/********************************************************************\
- * gnc_register_check_close *
- * *
- * Args: regData - the data struct for this register *
- * Return: none *
-\********************************************************************/
-static void
-gnc_sxed_reg_check_close(SchedXactionEditorDialog *sxed)
-{
- gboolean pending_changes;
- SplitRegister *reg;
- const char *message =
- _("The current template transaction "
- "has been changed. "
- "Would you like to record the changes?");
-
- reg = gnc_ledger_display_get_split_register (sxed->ledger);
- pending_changes = gnc_split_register_changed (reg);
- if (!pending_changes) {
- return;
- }
-
- if (gnc_verify_dialog(sxed->dialog, TRUE, message)) {
- Transaction *trans;
- trans = gnc_split_register_get_current_trans( reg );
- if ( !gnc_split_register_save( reg, TRUE ) )
- return;
-
- gnc_split_register_redraw( reg );
- } else {
- gnc_split_register_cancel_cursor_trans_changes (reg);
- }
-}
-
-static gboolean
-editor_component_sx_equality( gpointer find_data,
- gpointer user_data )
-{
- return ( (SchedXaction*)find_data
- == ((SchedXactionEditorDialog*)user_data)->sx );
-}
-
-static
-void
-gnc_sxd_row_click_handler( GtkCList *clist,
- gint col,
- gpointer ud )
-{
- SchedXactionDialog *sxd = (SchedXactionDialog*)ud;
-
- if ( col == sxd->currentSortCol ) {
- g_assert( sxd->currentSortType == GTK_SORT_ASCENDING
- || sxd->currentSortType == GTK_SORT_DESCENDING );
- switch ( sxd->currentSortType ) {
- case GTK_SORT_ASCENDING:
- sxd->currentSortType = GTK_SORT_DESCENDING;
- break;
- case GTK_SORT_DESCENDING:
- sxd->currentSortType = GTK_SORT_ASCENDING;
- break;
- default:
- PERR( "Unknown current sort type %d",
- sxd->currentSortType );
- }
- /* By defn, the current sort_compare method is correct. */
- gtk_clist_set_sort_column( clist, col );
- gtk_clist_set_sort_type( clist, sxd->currentSortType );
- gtk_clist_sort( clist );
- return;
- }
-
- sxd->currentSortCol = col;
- gnc_sxd_set_sort_compare( clist, sxd->currentSortCol );
- sxd->currentSortType = GTK_SORT_ASCENDING;
- gtk_clist_set_sort_column( clist, sxd->currentSortCol );
- gtk_clist_set_sort_type( clist, sxd->currentSortType );
- gtk_clist_sort( clist );
-}
-
-static
-gint
-gnc_sxd_clist_compare_sx_name( GtkCList *cl, gconstpointer a, gconstpointer b )
-{
- SchedXaction *sxa, *sxb;
-
- sxa = (SchedXaction*)(((GtkCListRow*)a)->data);
- sxb = (SchedXaction*)(((GtkCListRow*)b)->data);
- g_assert( sxa || sxb );
- if ( !sxa ) {
- return 1;
- }
- if ( !sxb ) {
- return -1;
- }
- return strcmp( xaccSchedXactionGetName( sxa ),
- xaccSchedXactionGetName( sxb ) );
-}
-
-static
-gint
-gnc_sxd_clist_compare_sx_freq( GtkCList *cl,
- gconstpointer a,
- gconstpointer b )
-{
- SchedXaction *sxa, *sxb;
-
- g_assert( a || b );
- if ( !a ) return 1;
- if ( !b ) return -1;
- sxa = (SchedXaction*)((GtkCListRow*)a)->data;
- sxb = (SchedXaction*)((GtkCListRow*)b)->data;
- g_assert( sxa || sxb );
- if ( !sxa ) return 1;
- if ( !sxb ) return -1;
- return gnc_freq_spec_compare( xaccSchedXactionGetFreqSpec( sxa ),
- xaccSchedXactionGetFreqSpec( sxb ) );
-}
-
-static
-gint
-gnc_sxd_clist_compare_sx_next_occur( GtkCList *cl,
- gconstpointer a,
- gconstpointer b )
-{
- SchedXaction *sxa, *sxb;
- GDate gda, gdb;
-
- sxa = (SchedXaction*)((GtkCListRow*)a)->data;
- sxb = (SchedXaction*)((GtkCListRow*)b)->data;
-
- g_assert( sxa || sxb );
- if ( !sxa ) {
- return 1;
- }
- if ( !sxb ) {
- return -1;
- }
- g_assert( sxa && sxb );
-
- gda = xaccSchedXactionGetNextInstance( sxa, NULL );
- gdb = xaccSchedXactionGetNextInstance( sxb, NULL );
-
- if ( ! ( g_date_valid(&gda) && g_date_valid(&gdb) ) ) {
- return 0;
- }
- if ( !g_date_valid(&gda) ) {
- return 1;
- }
- if ( !g_date_valid(&gdb) ) {
- return -1;
- }
- return g_date_compare( &gda, &gdb );
-}
-
-
-static
-void
-gnc_sxd_set_sort_compare( GtkCList *cl, gint col )
-{
- gint (*fn)( GtkCList *, gconstpointer, gconstpointer );
-
- fn = NULL;
- switch ( col ) {
- case 0: /* SX name */
- fn = gnc_sxd_clist_compare_sx_name;
- break;
- case 1: /* SX frequency */
- fn = gnc_sxd_clist_compare_sx_freq;
- break;
- case 2: /* next-occur date */
- fn = gnc_sxd_clist_compare_sx_next_occur;
- break;
- default: /* ?? */
- DEBUG( "invalid column value %d", col );
- g_assert( FALSE );
- }
- gtk_clist_set_compare_func( cl, NULL );
- gtk_clist_set_compare_func( cl, fn );
-}
-
-typedef enum { NO_END, DATE_END, COUNT_END } END_TYPE;
-
-static
-void
-gnc_sxed_update_cal( SchedXactionEditorDialog *sxed )
-{
- int i;
- FreqSpec *fs;
- GDate d;
- END_TYPE endType;
- GDate endDate;
- int numRemain;
-
- endType = NO_END;
- numRemain = -1;
- /* figure out the end restriction */
- if ( gtk_toggle_button_get_active( sxed->optEndDate ) ) {
- time_t tt;
- struct tm *tmpTm;
- endType = DATE_END;
- tt = gnc_date_edit_get_date( sxed->endDateEntry );
- tmpTm = g_new0( struct tm, 1 );
- *tmpTm = *(localtime( &tt ));
- g_date_set_day( &endDate, tmpTm->tm_mday );
- g_date_set_month( &endDate, tmpTm->tm_mon+1 );
- g_date_set_year( &endDate, tmpTm->tm_year + 1900 );
- g_free( tmpTm );
- } else if ( gtk_toggle_button_get_active( sxed->optEndNone ) ) {
- endType = NO_END;
- } else if ( gtk_toggle_button_get_active( sxed->optEndCount ) ) {
- endType = COUNT_END;
- numRemain =
- gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sxed->endRemainSpin) );
-
- } else {
- g_assert( FALSE );
- }
-
- if ( sxed->markId != -1 ) {
- gnc_dense_cal_mark_remove( sxed->example_cal, sxed->markId );
- sxed->markId = -1;
- }
-
- fs = xaccFreqSpecMalloc( gnc_get_current_book() );
- gnc_frequency_save_state( sxed->gncfreq, fs, &d );
- g_date_subtract_days( &d, 1 );
- xaccFreqSpecGetNextInstance( fs, &d, &d );
-
- /* Deal with the fact that this SX may have been run before [the
- * calendar should only show upcoming instances]... */
- {
- GDate *lastInst;
-
- lastInst = xaccSchedXactionGetLastOccurDate( sxed->sx );
- if ( g_date_valid( lastInst )
- && g_date_valid( &d )
- && g_date_compare( lastInst, &d ) != 0 ) {
- d = *lastInst;
- xaccFreqSpecGetNextInstance( fs, &d, &d );
- }
- }
-
- if ( !g_date_valid( &d ) ) {
- /* Nothing to do. */
- xaccFreqSpecFree( fs );
- return;
- }
-
- i = 0;
- gnc_dense_cal_set_month( sxed->example_cal, g_date_get_month( &d ) );
- gnc_dense_cal_set_year( sxed->example_cal, g_date_get_year( &d ) );
- while ( (i < EX_CAL_NUM_MONTHS * 31)
- && g_date_valid( &d )
- /* Restrict based on end date */
- && ( endType == NO_END
- || ( endType == DATE_END
- && g_date_compare( &d, &endDate ) <= 0 )
- || ( endType == COUNT_END
- && i < numRemain ) ) ) {
- *(sxed->cal_marks[i++]) = d;
- xaccFreqSpecGetNextInstance( fs, &d, &d );
- }
- if ( i <= 0 ) {
- xaccFreqSpecFree( fs );
- return;
- }
-
- {
- gchar *name;
- GString *info;
-
- name = gtk_editable_get_chars( sxed->nameEntry, 0, -1 );
- if ( strlen( name ) == 0 ) {
- g_free(name);
- name = NULL;
- }
- info = g_string_sized_new( 16 );
- xaccFreqSpecGetFreqStr( fs, info );
- sxed->markId = gnc_dense_cal_mark( sxed->example_cal, i,
- sxed->cal_marks,
- name, info->str );
- gtk_widget_queue_draw( GTK_WIDGET( sxed->example_cal ) );
-
- g_string_free( info, TRUE );
- if ( name != NULL )
- {
- g_free( name );
- }
- }
-
- xaccFreqSpecFree( fs );
-}
-
-static
-void
-gnc_sxed_freq_changed( GNCFrequency *gf, gpointer ud )
-{
- gnc_sxed_update_cal( (SchedXactionEditorDialog*)ud );
-}
-
-static
-void
-sxed_excal_update_adapt( GtkObject *o, gpointer ud )
-{
- gnc_sxed_update_cal( (SchedXactionEditorDialog*)ud );
-}
-
-void on_sx_check_toggled (GtkWidget *togglebutton, gpointer user_data);
-
-void
-on_sx_check_toggled (GtkWidget *togglebutton,
- gpointer user_data)
-{
- GtkWidget *widget;
- gboolean create; // , notify;
-
- /* The gnc_glade_lookup_widget() function works because all of these
- * widgets come from the same glade file. */
- widget = gnc_glade_lookup_widget(togglebutton,
- "gconf/dialogs/scheduled_trans/transaction_editor/create_auto");
- create = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
- widget = gnc_glade_lookup_widget(togglebutton,
- "gconf/dialogs/scheduled_trans/transaction_editor/notify");
- gtk_widget_set_sensitive(widget, create);
-}
-
-typedef struct _acct_deletion_handler_data
-{
- GList *affected_sxes;
- GtkWidget *dialog;
-} acct_deletion_handler_data;
-
-static void
-_open_editors(GtkDialog *dialog, gint response_code, gpointer data)
-{
- acct_deletion_handler_data *adhd = (acct_deletion_handler_data *)data;
- gtk_widget_hide_all(adhd->dialog);
- {
- GList *sx_iter;
- for (sx_iter = adhd->affected_sxes; sx_iter; sx_iter = sx_iter->next)
- {
- gnc_ui_scheduled_xaction_editor_dialog_create(NULL,
- (SchedXaction*)sx_iter->data,
- FALSE);
- }
- }
- g_list_free(adhd->affected_sxes);
- gtk_widget_destroy(GTK_WIDGET(adhd->dialog));
- g_free(adhd);
-}
-
-static void
-_sx_engine_event_handler(QofEntity *ent, QofEventId event_type, gpointer user_data, gpointer evt_data)
-{
- Account *acct;
- QofBook *book;
- GList *affected_sxes;
-
- if (!(event_type & QOF_EVENT_DESTROY))
- return;
- if (!GNC_IS_ACCOUNT(ent))
- return;
- acct = GNC_ACCOUNT(ent);
- book = qof_instance_get_book(QOF_INSTANCE(acct));
- affected_sxes = gnc_sx_get_sxes_referencing_account(book, acct);
-
- if (g_list_length(affected_sxes) == 0)
- return;
-
- {
- GList *sx_iter;
- acct_deletion_handler_data *data;
- GladeXML *xml;
- GtkWidget *dialog;
- GtkListStore *name_list;
- GtkTreeView *list;
- GtkTreeViewColumn *name_column;
- GtkCellRenderer *renderer;
-
- xml = gnc_glade_xml_new("sched-xact.glade", "Account Deletion");
- dialog = glade_xml_get_widget(xml, "Account Deletion");
- list = GTK_TREE_VIEW(glade_xml_get_widget(xml, "sx_list"));
-
- data = (acct_deletion_handler_data*)g_new0(acct_deletion_handler_data, 1);
- data->dialog = dialog;
- data->affected_sxes = affected_sxes;
- name_list = gtk_list_store_new(1, G_TYPE_STRING);
- for (sx_iter = affected_sxes; sx_iter != NULL; sx_iter = sx_iter->next)
- {
- SchedXaction *sx;
- GtkTreeIter iter;
- gchar *sx_name;
-
- sx = (SchedXaction*)sx_iter->data;
- sx_name = xaccSchedXactionGetName(sx);
- gtk_list_store_append(name_list, &iter);
- gtk_list_store_set(name_list, &iter, 0, sx_name, -1);
- }
- gtk_tree_view_set_model(list, GTK_TREE_MODEL(name_list));
- g_object_unref(G_OBJECT(name_list));
-
- renderer = gtk_cell_renderer_text_new();
- name_column = gtk_tree_view_column_new_with_attributes(_("Name"),
- renderer,
- "text", 0, NULL);
- gtk_tree_view_append_column(list, name_column);
-
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(_open_editors), data);
-
- gtk_widget_show_all(GTK_WIDGET(dialog));
- }
-}
-
-void
-gnc_ui_sx_initialize (void)
-{
- _sx_engine_event_handler_id = qof_event_register_handler(_sx_engine_event_handler, NULL);
-
- gnc_hook_add_dangler(HOOK_BOOK_OPENED,
- (GFunc)gnc_sx_sxsincelast_book_opened, NULL);
- gnc_preferences_add_page (SX_GLADE_FILE,
- "sx_prefs",
- _("Scheduled Transactions"));
-}
Deleted: gnucash/trunk/src/gnome/dialog-scheduledxaction.h
===================================================================
--- gnucash/trunk/src/gnome/dialog-scheduledxaction.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/dialog-scheduledxaction.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,67 +0,0 @@
-/********************************************************************\
- * dialog-scheduledxaction.h : dialogs for scheduled transactions *
- * Copyright (C) 2001 Joshua Sled <jsled at asynchronous.org> *
- * *
- * 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 *
-\********************************************************************/
-
-#ifndef DIALOG_SCHEDULEDXACTION_H
-#define DIALOG_SCHEDULEDXACTION_H
-
-#include "SchedXaction.h"
-
-#define DIALOG_SCHEDXACTION_CM_CLASS "dialog-scheduledtransactions"
-#define DIALOG_SCHEDXACTION_EDITOR_CM_CLASS "dialog-scheduledtransaction-editor"
-
-#define SXED_GCONF_SECTION "dialogs/scheduled_trans/transaction_editor"
-#define KEY_CREATE_AUTO "create_auto"
-#define KEY_NOTIFY "notify"
-#define KEY_CREATE_DAYS "create_days"
-#define KEY_REMIND_DAYS "remind_days"
-
-struct _SchedXactionDialog;
-struct _SchedXactionEditorDialog;
-
-typedef struct _SchedXactionDialog SchedXactionDialog;
-typedef struct _SchedXactionEditorDialog SchedXactionEditorDialog;
-
-SchedXactionDialog * gnc_ui_scheduled_xaction_dialog_create(void);
-void gnc_ui_scheduled_xaction_dialog_destroy(SchedXactionDialog *sxd);
-#ifdef __GTK_CLIST_H__
-void row_select_handler( GtkCList *clist, gint row, gint col,
- GdkEventButton *event, gpointer d );
-void row_unselect_handler( GtkCList *clist, gint row, gint col,
- GdkEventButton *event, gpointer d );
-#endif
-
-void gnc_sxd_list_refresh( SchedXactionDialog *sxd );
-
-SchedXactionEditorDialog *
-gnc_ui_scheduled_xaction_editor_dialog_create( SchedXactionDialog *sxd,
- SchedXaction *sx,
- gboolean newSX );
-
-void gnc_ui_scheduled_xaction_editor_dialog_destroy( SchedXactionEditorDialog *sxd );
-
-/**
- * Sets up a book opened hook. The function called may open a "since
- * last run" dialog based upon the user's preferences.
- **/
-void gnc_ui_sx_initialize (void);
-
-#endif
Copied: gnucash/trunk/src/gnome/dialog-sx-editor.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.c)
Copied: gnucash/trunk/src/gnome/dialog-sx-editor.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.h)
Modified: gnucash/trunk/src/gnome/dialog-sx-from-trans.c
===================================================================
--- gnucash/trunk/src/gnome/dialog-sx-from-trans.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/dialog-sx-from-trans.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -25,26 +25,25 @@
#include "config.h"
-#include <stdlib.h>
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include "glib-compat.h"
-
-#include "gnc-engine.h"
-#include "SX-book.h"
-#include "SX-book-p.h"
-#include "SX-ttinfo.h"
-#include "SchedXaction.h"
-#include "gnc-component-manager.h"
-#include "dialog-scheduledxaction.h"
+#include "dialog-sx-editor.h"
#include "dialog-sx-from-trans.h"
#include "dialog-utils.h"
+#include "glib-compat.h"
+#include "gnc-component-manager.h"
#include "gnc-date-edit.h"
-#include "qof.h"
+#include "gnc-dense-cal-store.h"
+#include "gnc-dense-cal.h"
+#include "gnc-engine.h"
#include "gnc-gconf-utils.h"
-#include "gnc-ui.h"
#include "gnc-ui-util.h"
-#include "gnc-dense-cal.h"
+#include "gnc-ui.h"
+#include "qof.h"
+#include "SchedXaction.h"
+#include "SX-book.h"
+#include "SX-ttinfo.h"
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <stdlib.h>
#define SX_GLADE_FILE "sched-xact.glade"
#define SXFTD_DIALOG_GLADE_NAME "sx_from_real_trans"
@@ -78,11 +77,8 @@
static void sxftd_destroy( GtkWidget *w, gpointer user_data );
-typedef enum { NEVER_END, END_ON_DATE, END_AFTER_N_OCCS, BAD_END } endType;
-
typedef enum { FREQ_DAILY = 0, /* I know the =0 is redundant, but I'm using
- * the numeric equivalences explicitly here
- */
+ * the numeric equivalences explicitly here */
FREQ_WEEKLY,
FREQ_BIWEEKLY,
FREQ_MONTHLY,
@@ -97,11 +93,8 @@
Transaction *trans;
SchedXaction *sx;
+ GncDenseCalStore *dense_cal_model;
GncDenseCal *example_cal;
- /** Storage for the maximum possible number of marks we could put on the
- * calendar. */
- GDate **cal_marks;
- gint mark_id;
GNCDateEdit *startDateGDE, *endDateGDE;
@@ -109,7 +102,7 @@
typedef struct
{
- endType type;
+ gdcs_end_type type;
GDate end_date;
guint n_occurrences;
} getEndTuple;
@@ -117,9 +110,6 @@
static void sxftd_update_example_cal( SXFromTransInfo *sxfti );
static void sxftd_update_excal_adapt( GObject *o, gpointer ud );
-/* Stolen from jsled - nice and neat, actually (if a little light on
- * for typechecking, but we'll be careful) . . .
- */
typedef struct
{
gchar *name;
@@ -127,11 +117,9 @@
void (*handlerFn)();
} widgetSignalHandlerTuple;
-
static void sxftd_ok_clicked(SXFromTransInfo *sxfti);
static void sxftd_advanced_clicked(SXFromTransInfo *sxfti);
-
static void
sxfti_attach_callbacks(SXFromTransInfo *sxfti)
{
@@ -144,7 +132,6 @@
{ SXFTD_END_ON_DATE_BUTTON, "clicked", sxftd_update_excal_adapt },
{ SXFTD_N_OCCURRENCES_BUTTON, "clicked", sxftd_update_excal_adapt },
{ SXFTD_N_OCCURRENCES_ENTRY, "changed", sxftd_update_excal_adapt },
-
{ NULL, NULL, NULL }
};
@@ -370,20 +357,19 @@
/* Setup the example calendar and related data structures. */
{
- int i;
+ int num_marks = SXFTD_EXCAL_NUM_MONTHS * 31;
w = GTK_WIDGET(glade_xml_get_widget( sxfti->gxml, SXFTD_EX_CAL_FRAME ));
- sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new());
+ sxfti->dense_cal_model = gnc_dense_cal_store_new(num_marks);
+ sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(sxfti->dense_cal_model)));
+ // gobject-2.10: g_object_ref_sink(sxfti->example_cal);
+ g_object_ref(G_OBJECT(sxfti->example_cal));
+ gtk_object_sink(GTK_OBJECT(sxfti->example_cal));
+
g_assert( sxfti->example_cal );
gnc_dense_cal_set_num_months( sxfti->example_cal, SXFTD_EXCAL_NUM_MONTHS );
gnc_dense_cal_set_months_per_col( sxfti->example_cal, SXFTD_EXCAL_MONTHS_PER_COL );
gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxfti->example_cal) );
-
- sxfti->mark_id = -1;
- sxfti->cal_marks = g_new0( GDate*, (SXFTD_EXCAL_NUM_MONTHS * 31) );
- for ( i=0; i < SXFTD_EXCAL_NUM_MONTHS * 31; i++ ) {
- sxfti->cal_marks[i] = g_date_new();
- }
}
/* Setup the start and end dates as GNCDateEdits */
@@ -551,7 +537,7 @@
sxftd_ok_clicked(SXFromTransInfo *sxfti)
{
QofBook *book;
- GList *sx_list;
+ SchedXactions *sxes;
guint sx_error = sxftd_compute_sx(sxfti);
if (sx_error != 0
@@ -559,23 +545,14 @@
PERR( "Error in sxftd_compute_sx after ok_clicked [%d]", sx_error );
}
else {
- SchedXactionDialog *sxd;
-
if ( sx_error == SXFTD_ERRNO_UNBALANCED_XACTION ) {
gnc_error_dialog( gnc_ui_get_toplevel(),
_( "The Scheduled Transaction is unbalanced. "
"You are strongly encouraged to correct this situation." ) );
}
book = gnc_get_current_book ();
- sx_list = gnc_book_get_schedxactions(book);
- sx_list = g_list_append(sx_list, sxfti->sx);
- gnc_book_set_schedxactions(book, sx_list);
- sxd = (SchedXactionDialog*)
- gnc_find_first_gui_component(
- DIALOG_SCHEDXACTION_CM_CLASS, NULL, NULL );
- if ( sxd ) {
- gnc_sxd_list_refresh( sxd );
- }
+ sxes = gnc_book_get_schedxactions(book);
+ gnc_sxes_add_sx(sxes, sxfti->sx);
}
sxftd_close(sxfti, FALSE);
@@ -617,8 +594,7 @@
sxftd_advanced_clicked(SXFromTransInfo *sxfti)
{
guint sx_error = sxftd_compute_sx(sxfti);
- SchedXactionDialog *adv_dlg;
- SchedXactionEditorDialog *adv_edit_dlg;
+ GncSxEditorDialog *adv_edit_dlg;
GMainContext *context;
if ( sx_error != 0
@@ -634,10 +610,8 @@
context = g_main_context_default();
while (g_main_context_iteration(context, FALSE));
- adv_dlg = gnc_ui_scheduled_xaction_dialog_create();
adv_edit_dlg =
- gnc_ui_scheduled_xaction_editor_dialog_create(adv_dlg,
- sxfti->sx,
+ gnc_ui_scheduled_xaction_editor_dialog_create(sxfti->sx,
TRUE /* newSX */);
/* close ourself, since advanced editing entails us, and there are sync
* issues otherwise. */
@@ -647,28 +621,21 @@
static void
sxftd_destroy( GtkWidget *w, gpointer user_data )
{
- int i;
SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data;
- for ( i=0; i<SXFTD_EXCAL_NUM_MONTHS*31; i++ ) {
- g_date_free( sxfti->cal_marks[i] );
- }
- g_free( sxfti->cal_marks );
-
if ( sxfti->sx ) {
xaccSchedXactionFree(sxfti->sx);
sxfti->sx = NULL;
}
+ g_object_unref(G_OBJECT(sxfti->dense_cal_model));
+ g_object_unref(G_OBJECT(sxfti->example_cal));
+
/* FIXME: do we need to clean up the GladeXML pointer? */
g_free(sxfti);
}
-
-/**
- *
- **/
static void
gnc_sx_trans_window_response_cb (GtkDialog *dialog,
gint response,
@@ -696,7 +663,6 @@
LEAVE(" ");
}
-
/**
* Update the example calendar; make sure to take into account the end
* specification.
@@ -707,11 +673,8 @@
struct tm *tmpTm;
time_t tmp_tt;
GDate date, startDate;
- unsigned int i;
FreqSpec *fs;
getEndTuple get;
- gchar *name;
- GString *info;
fs = xaccFreqSpecMalloc( gnc_get_current_book() );
get = sxftd_get_end_info( sxfti );
@@ -733,43 +696,27 @@
xaccFreqSpecGetNextInstance( fs, &date, &date );
startDate = date;
- i = 0;
- while ( (i < (SXFTD_EXCAL_NUM_MONTHS * 31))
- && g_date_valid( &date )
- /* Do checking against end restriction. */
- && ( ( get.type == NEVER_END )
- || ( get.type == END_ON_DATE
- && g_date_compare( &date, &(get.end_date) ) <= 0 )
- || ( get.type == END_AFTER_N_OCCS
- && i < get.n_occurrences ) ) ) {
-
- *sxfti->cal_marks[i++] = date;
- xaccFreqSpecGetNextInstance( fs, &date, &date );
+ switch (get.type)
+ {
+ case NEVER_END:
+ gnc_dense_cal_store_update_no_end(sxfti->dense_cal_model, &startDate, fs);
+ break;
+ case END_ON_DATE:
+ gnc_dense_cal_store_update_date_end(sxfti->dense_cal_model, &startDate, fs, &get.end_date);
+ break;
+ case END_AFTER_N_OCCS:
+ gnc_dense_cal_store_update_count_end(sxfti->dense_cal_model, &startDate, fs, get.n_occurrences);
+ break;
+ default:
+ printf("unknown get.type [%d]\n", get.type);
+ break;
}
- /* remove old marks */
- if ( sxfti->mark_id != -1 ) {
- gnc_dense_cal_mark_remove( sxfti->example_cal, sxfti->mark_id );
- sxfti->mark_id = -1;
- }
- if ( i > 0 ) {
- GtkWidget *w;
- gnc_dense_cal_set_month( sxfti->example_cal,
- g_date_get_month( &startDate ) );
- gnc_dense_cal_set_year( sxfti->example_cal,
- g_date_get_year( &startDate ) );
- w = glade_xml_get_widget( sxfti->gxml, SXFTD_NAME_ENTRY );
- name = gtk_editable_get_chars( GTK_EDITABLE(w), 0, -1 );
- info = g_string_sized_new( 16 );
- xaccFreqSpecGetFreqStr( fs, info );
- sxfti->mark_id =
- gnc_dense_cal_mark( sxfti->example_cal,
- i, sxfti->cal_marks,
- name, info->str );
- gtk_widget_queue_draw( GTK_WIDGET(sxfti->example_cal) );
- g_free( name );
- g_string_free( info, TRUE );
- }
+ gnc_dense_cal_set_month( sxfti->example_cal,
+ g_date_get_month( &startDate ) );
+ gnc_dense_cal_set_year( sxfti->example_cal,
+ g_date_get_year( &startDate ) );
+
xaccFreqSpecFree( fs );
}
@@ -784,10 +731,6 @@
sxftd_update_example_cal( sxfti );
}
-
-/**
- *
- **/
void
gnc_sx_create_from_trans( Transaction *trans )
{
Copied: gnucash/trunk/src/gnome/dialog-sx-since-last-run.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/dialog-sx-since-last-run.c)
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-sx-since-last-run.c 2007-01-15 01:57:07 UTC (rev 15384)
+++ gnucash/trunk/src/gnome/dialog-sx-since-last-run.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -0,0 +1,1105 @@
+/********************************************************************\
+ * dialog-sx-since-last-run.c : dialog for scheduled transaction *
+ * since-last-run processing. *
+ * Copyright (C) 2006 Joshua Sled <jsled at asynchronous.org> *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General Public *
+ * License as published by the Free Software Foundation. *
+ * *
+ * 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 *
+\********************************************************************/
+
+#include "config.h"
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <glade/glade-xml.h>
+
+#include "dialog-utils.h"
+#include "gnc-exp-parser.h"
+#include "gnc-sx-instance-model.h"
+#include "dialog-sx-since-last-run.h"
+
+#include "gnc-ui-util.h"
+#include "Query.h"
+#include "QueryNew.h"
+#include "gnc-ledger-display.h"
+#include "gnc-plugin-page-register.h"
+#include "gnc-main-window.h"
+#include "gnc-component-manager.h"
+#include "gnc-gconf-utils.h"
+#include "gnc-gui-query.h"
+
+// static QofLogModule log_module = GNC_MOD_GUI;
+
+#define GCONF_SECTION "dialogs/scheduled_trans/since_last_run"
+
+struct _GncSxSinceLastRunDialog
+{
+ GtkWidget *dialog;
+ GncSxSlrTreeModelAdapter *editing_model;
+ GtkTreeView *instance_view;
+ GtkToggleButton *review_created_txns_toggle;
+};
+
+/* ------------------------------------------------------------ */
+
+static GObjectClass *parent_class = NULL;
+
+struct _GncSxSlrTreeModelAdapter
+{
+ GObject parent;
+
+ /* protected: */
+ gulong updated_cb_id;
+ gboolean disposed;
+
+ GncSxInstanceModel *instances;
+ GtkTreeStore *real;
+};
+
+typedef struct _GncSxSlrTreeModelAdapterClass
+{
+ GObjectClass parent;
+} GncSxSlrTreeModelAdapterClass;
+
+GType gnc_sx_slr_tree_model_adapter_get_type(void);
+static void gnc_sx_slr_tree_model_adapter_class_init(GncSxSlrTreeModelAdapterClass *klass);
+static void gnc_sx_slr_tree_model_adapter_interface_init(gpointer g_iface, gpointer iface_data);
+static void gnc_sx_slr_tree_model_adapter_init(GTypeInstance *instance, gpointer klass);
+GncSxSlrTreeModelAdapter* gnc_sx_slr_tree_model_adapter_new(GncSxInstanceModel *instances);
+static void gnc_sx_slr_tree_model_adapter_dispose(GObject *obj);
+static void gnc_sx_slr_tree_model_adapter_finalize(GObject *obj);
+
+GncSxInstanceModel* gnc_sx_slr_tree_model_adapter_get_instance_model(GncSxSlrTreeModelAdapter *slr_model);
+GncSxInstances* gnc_sx_slr_tree_model_adapter_get_sx_instances(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter);
+static GncSxInstances* _gnc_sx_slr_tree_model_adapter_get_sx_instances(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter, gboolean check_depth);
+/** @return null if the iter is not actually an GncSxInstance. **/
+GncSxInstance* gnc_sx_slr_model_get_instance(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter);
+static GncSxInstance* _gnc_sx_slr_model_get_instance(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter, gboolean check_depth);
+/** @return false if the iter is not actaully an GncSxInstance's variable. **/
+gboolean gnc_sx_slr_model_get_instance_and_variable(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter, GncSxInstance **instance_loc, GncSxVariable **var_loc);
+
+void gnc_sx_slr_model_change_instance_state(GncSxSlrTreeModelAdapter *model, GncSxInstance *instance, GncSxInstanceState new_state);
+void gnc_sx_slr_model_change_variable(GncSxSlrTreeModelAdapter *model, GncSxInstance *instance, GncSxVariable *variable, gnc_numeric *new_value);
+void gnc_sx_slr_model_effect_change(GncSxSlrTreeModelAdapter *model, gboolean auto_create_only, GList **created_transaction_guids, GList **creation_errors);
+
+GtkTreeModel* gnc_sx_get_slr_state_model(void);
+
+#define GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER (gnc_sx_slr_tree_model_adapter_get_type ())
+#define GNC_SX_SLR_TREE_MODEL_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER, GncSxSlrTreeModelAdapter))
+#define GNC_SX_SLR_TREE_MODEL_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER, GncSxSlrTreeModelAdapterClass))
+#define GNC_IS_SX_SLR_TREE_MODEL_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER))
+#define GNC_IS_SX_SLR_TREE_MODEL_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER))
+#define GNC_SX_SLR_TREE_MODEL_ADAPTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER, GncSxSlrTreeModelAdapterClass))
+
+/* ------------------------------------------------------------ */
+
+static void _show_created_transactions(GncSxSinceLastRunDialog *app_dialog, GList *created_txn_guids);
+
+static void dialog_response_cb(GtkDialog *dialog, gint response_id, GncSxSinceLastRunDialog *app_dialog);
+
+/* ------------------------------------------------------------ */
+
+static void
+_var_numeric_to_string(gnc_numeric *value, GString **str)
+{
+ *str = g_string_sized_new(5);
+ g_string_printf(*str, "%0.2f", gnc_numeric_to_double(*value));
+}
+
+/* ------------------------------------------------------------ */
+
+GType
+gnc_sx_slr_tree_model_adapter_get_type(void)
+{
+ static GType gsstma_type = 0;
+ if (gsstma_type == 0) {
+ static const GTypeInfo info = {
+ sizeof (GncSxSlrTreeModelAdapterClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc)gnc_sx_slr_tree_model_adapter_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GncSxSlrTreeModelAdapter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc)gnc_sx_slr_tree_model_adapter_init /* instance_init */
+ };
+ static const GInterfaceInfo itreeModel_info = {
+ (GInterfaceInitFunc) gnc_sx_slr_tree_model_adapter_interface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ gsstma_type = g_type_register_static (G_TYPE_OBJECT,
+ "GncSxSlrTreeModelAdapterType",
+ &info, 0);
+ g_type_add_interface_static(gsstma_type,
+ GTK_TYPE_TREE_MODEL,
+ &itreeModel_info);
+ }
+ return gsstma_type;
+}
+
+static void
+gnc_sx_slr_tree_model_adapter_class_init(GncSxSlrTreeModelAdapterClass *klass)
+{
+ GObjectClass *obj_class;
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->dispose = gnc_sx_slr_tree_model_adapter_dispose;
+ obj_class->finalize = gnc_sx_slr_tree_model_adapter_finalize;
+}
+
+static GtkTreeModelFlags
+gsslrtma_get_flags(GtkTreeModel *tree_model)
+{
+ return gtk_tree_model_get_flags(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real));
+}
+
+static gint
+gsslrtma_get_n_columns(GtkTreeModel *tree_model)
+{
+ return gtk_tree_model_get_n_columns(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real));
+}
+
+static GType
+gsslrtma_get_column_type(GtkTreeModel *tree_model, gint index)
+{
+ return gtk_tree_model_get_column_type(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), index);
+}
+
+static gboolean
+gsslrtma_get_iter(GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ return gtk_tree_model_get_iter(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter, path);
+}
+
+static GtkTreePath*
+gsslrtma_get_path(GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return gtk_tree_model_get_path(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter);
+}
+
+static void
+gsslrtma_get_value(GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ gtk_tree_model_get_value(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter, column, value);
+}
+
+static gboolean
+gsslrtma_iter_next(GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return gtk_tree_model_iter_next(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter);
+}
+
+static gboolean
+gsslrtma_iter_children(GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ return gtk_tree_model_iter_children(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter, parent);
+}
+
+static gboolean
+gsslrtma_iter_has_child(GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return gtk_tree_model_iter_has_child(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter);
+}
+
+static gint
+gsslrtma_iter_n_children(GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter);
+}
+
+static gboolean
+gsslrtma_iter_nth_child(GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ return gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter, parent, n);
+}
+
+static gboolean
+gsslrtma_iter_parent(GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return gtk_tree_model_iter_parent(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter, child);
+}
+
+static void
+gsslrtma_ref_node(GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ gtk_tree_model_ref_node(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter);
+}
+
+static void
+gsslrtma_unref_node(GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ gtk_tree_model_unref_node(GTK_TREE_MODEL(GNC_SX_SLR_TREE_MODEL_ADAPTER(tree_model)->real), iter);
+}
+
+static void
+gnc_sx_slr_tree_model_adapter_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ GtkTreeModelIface *tree_model = (GtkTreeModelIface*)g_iface;
+ tree_model->get_flags = gsslrtma_get_flags;
+ tree_model->get_n_columns = gsslrtma_get_n_columns;
+ tree_model->get_column_type = gsslrtma_get_column_type;
+ tree_model->get_iter = gsslrtma_get_iter;
+ tree_model->get_path = gsslrtma_get_path;
+ tree_model->get_value = gsslrtma_get_value;
+ tree_model->iter_next = gsslrtma_iter_next;
+ tree_model->iter_children = gsslrtma_iter_children;
+ tree_model->iter_has_child = gsslrtma_iter_has_child;
+ tree_model->iter_n_children = gsslrtma_iter_n_children;
+ tree_model->iter_nth_child = gsslrtma_iter_nth_child;
+ tree_model->iter_parent = gsslrtma_iter_parent;
+ tree_model->ref_node = gsslrtma_ref_node;
+ tree_model->unref_node = gsslrtma_unref_node;
+}
+
+static void
+gsslrtma_proxy_row_changed(GtkTreeModel *treemodel,
+ GtkTreePath *arg1,
+ GtkTreeIter *arg2,
+ gpointer user_data)
+{
+ g_signal_emit_by_name(user_data, "row-changed", arg1, arg2);
+}
+
+static void
+gsslrtma_proxy_row_deleted(GtkTreeModel *treemodel,
+ GtkTreePath *arg1,
+ gpointer user_data)
+{
+ g_signal_emit_by_name(user_data, "row-deleted", arg1);
+}
+
+static void
+gsslrtma_proxy_row_has_child_toggled(GtkTreeModel *treemodel,
+ GtkTreePath *arg1,
+ GtkTreeIter *arg2,
+ gpointer user_data)
+{
+ g_signal_emit_by_name(user_data, "row-has-child-toggled", arg1, arg2);
+}
+
+static void
+gsslrtma_proxy_row_inserted(GtkTreeModel *treemodel,
+ GtkTreePath *arg1,
+ GtkTreeIter *arg2,
+ gpointer user_data)
+{
+ g_signal_emit_by_name(user_data, "row-inserted", arg1, arg2);
+}
+
+static void
+gsslrtma_proxy_rows_reordered(GtkTreeModel *treemodel,
+ GtkTreePath *arg1,
+ GtkTreeIter *arg2,
+ gpointer arg3,
+ gpointer user_data)
+{
+ g_signal_emit_by_name(user_data, "rows-reordered", arg1, arg2, arg3);
+}
+
+// model columns
+enum {
+ SLR_MODEL_COL_NAME = 0,
+ SLR_MODEL_COL_INSTANCE_STATE,
+ SLR_MODEL_COL_VARAIBLE_VALUE,
+ SLR_MODEL_COL_INSTANCE_VISIBILITY,
+ SLR_MODEL_COL_VARIABLE_VISIBILITY,
+ SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY,
+};
+
+static void
+gnc_sx_slr_tree_model_adapter_init(GTypeInstance *instance, gpointer klass)
+{
+ GncSxSlrTreeModelAdapter *adapter = GNC_SX_SLR_TREE_MODEL_ADAPTER(instance);
+ // columns: thing-name, instance-state, variable-value, instance-visible, variable-visible, instance_state_sensitivity
+ // at depth=0: <sx>, N/A, N/A, N/A N/A, N/A
+ // at depth=1: <instance>, <state>, N/A, <valid>, N/A, <valid>
+ // at depth=2: <variable>, N/A, <value>, N/A, <valid>, N/A
+ adapter->real = gtk_tree_store_new(6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+
+ g_signal_connect(adapter->real, "row-changed", G_CALLBACK(gsslrtma_proxy_row_changed), adapter);
+ g_signal_connect(adapter->real, "row-deleted", G_CALLBACK(gsslrtma_proxy_row_deleted), adapter);
+ g_signal_connect(adapter->real, "row-has-child-toggled", G_CALLBACK(gsslrtma_proxy_row_has_child_toggled), adapter);
+ g_signal_connect(adapter->real, "row-inserted", G_CALLBACK(gsslrtma_proxy_row_inserted), adapter);
+ g_signal_connect(adapter->real, "rows-reordered", G_CALLBACK(gsslrtma_proxy_rows_reordered), adapter);
+}
+
+/* @@fixme: i18n. **/
+/* @@fixme: non-staticize. **/
+static char* gnc_sx_instance_state_names[] = {
+ ("Ignored"),
+ ("Postponed"),
+ ("To-Create"),
+ ("Reminder"),
+ ("Created"),
+ NULL
+};
+
+static GtkTreeModel* _singleton_slr_state_model = NULL;
+
+GtkTreeModel*
+gnc_sx_get_slr_state_model(void)
+{
+ if (_singleton_slr_state_model == NULL)
+ {
+ int i;
+ GtkTreeIter iter;
+
+ _singleton_slr_state_model = GTK_TREE_MODEL(gtk_list_store_new(1, G_TYPE_STRING));
+ for (i = 0; i != SX_INSTANCE_STATE_CREATED; i++)
+ {
+ gtk_list_store_insert_with_values(GTK_LIST_STORE(_singleton_slr_state_model),
+ &iter,
+ SX_INSTANCE_STATE_MAX_STATE + 1,
+ 0, gnc_sx_instance_state_names[i], -1);
+ }
+ }
+ return _singleton_slr_state_model;
+}
+
+static void
+_consume_excess_rows(GtkTreeStore *store, int last_index, GtkTreeIter *parent_iter, GtkTreeIter *maybe_invalid_iter)
+{
+ if (last_index == -1)
+ {
+ // try to get whatever was there beforehand, if it exists
+ if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(store), maybe_invalid_iter, parent_iter))
+ return;
+ }
+ else
+ {
+ // increment the iter, or bail out.
+ if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(store), maybe_invalid_iter))
+ return;
+ }
+
+ // consume until we're done.
+ while (gtk_tree_store_remove(store, maybe_invalid_iter));
+}
+
+
+static void
+gsslrtma_populate_tree_store(GncSxSlrTreeModelAdapter *model)
+{
+ GtkTreeIter sx_tree_iter;
+ GList *sx_iter;
+ int instances_index = -1;
+
+ for (sx_iter = model->instances->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
+ {
+ GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
+ FreqSpec *fs;
+ GString *frequency_str;
+ char last_occur_date_buf[MAX_DATE_LENGTH+1];
+ char next_occur_date_buf[MAX_DATE_LENGTH+1];
+
+ frequency_str = g_string_sized_new(32);
+ fs = xaccSchedXactionGetFreqSpec(instances->sx);
+ xaccFreqSpecGetFreqStr(fs, frequency_str);
+
+ {
+ GDate *last_occur = xaccSchedXactionGetLastOccurDate(instances->sx);
+ if (last_occur == NULL || !g_date_valid(last_occur))
+ {
+ g_stpcpy(last_occur_date_buf, "never");
+ }
+ else
+ {
+ qof_print_gdate(last_occur_date_buf,
+ MAX_DATE_LENGTH,
+ last_occur);
+ }
+ }
+
+ qof_print_gdate(next_occur_date_buf, MAX_DATE_LENGTH, &instances->next_instance_date);
+
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real), &sx_tree_iter, NULL, ++instances_index))
+ {
+ gtk_tree_store_append(model->real, &sx_tree_iter, NULL);
+ }
+ gtk_tree_store_set(model->real, &sx_tree_iter,
+ SLR_MODEL_COL_NAME, xaccSchedXactionGetName(instances->sx),
+ SLR_MODEL_COL_INSTANCE_STATE, NULL,
+ SLR_MODEL_COL_VARAIBLE_VALUE, NULL,
+ SLR_MODEL_COL_INSTANCE_VISIBILITY, FALSE,
+ SLR_MODEL_COL_VARIABLE_VISIBILITY, FALSE,
+ SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY, FALSE,
+ -1);
+ g_string_free(frequency_str, TRUE);
+
+ // Insert instance information
+ {
+ GList *inst_iter;
+ GtkTreeIter inst_tree_iter;
+ char instance_date_buf[MAX_DATE_LENGTH+1];
+ int instance_index = -1;
+
+ for (inst_iter = instances->list; inst_iter != NULL; inst_iter = inst_iter->next)
+ {
+ GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
+ qof_print_gdate(instance_date_buf, MAX_DATE_LENGTH, &inst->date);
+
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real), &inst_tree_iter, &sx_tree_iter, ++instance_index))
+ {
+ gtk_tree_store_append(model->real, &inst_tree_iter, &sx_tree_iter);
+ }
+ gtk_tree_store_set(model->real, &inst_tree_iter,
+ SLR_MODEL_COL_NAME, instance_date_buf,
+ SLR_MODEL_COL_INSTANCE_STATE, gnc_sx_instance_state_names[inst->state],
+ SLR_MODEL_COL_VARAIBLE_VALUE, NULL,
+ SLR_MODEL_COL_INSTANCE_VISIBILITY, TRUE,
+ SLR_MODEL_COL_VARIABLE_VISIBILITY, FALSE,
+ SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY, inst->state != SX_INSTANCE_STATE_CREATED,
+ -1);
+
+ // Insert variable information
+ {
+ GList *vars = NULL, *var_iter;
+ GtkTreeIter var_tree_iter;
+ gint visible_variable_index = -1;
+
+ vars = gnc_sx_instance_get_variables(inst);
+ for (var_iter = vars; var_iter != NULL; var_iter = var_iter->next)
+ {
+ GncSxVariable *var = (GncSxVariable*)var_iter->data;
+ GString *tmp_str;
+
+ if (!var->editable)
+ continue;
+
+ if (gnc_numeric_check(var->value) == GNC_ERROR_OK)
+ {
+ _var_numeric_to_string(&var->value, &tmp_str);
+ }
+ else
+ {
+ tmp_str = g_string_new("(need value)");
+ }
+
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real),
+ &var_tree_iter, &inst_tree_iter,
+ ++visible_variable_index))
+ {
+ gtk_tree_store_append(model->real, &var_tree_iter, &inst_tree_iter);
+ }
+ gtk_tree_store_set(model->real, &var_tree_iter,
+ SLR_MODEL_COL_NAME, var->name,
+ SLR_MODEL_COL_INSTANCE_STATE, NULL,
+ SLR_MODEL_COL_VARAIBLE_VALUE, tmp_str->str,
+ SLR_MODEL_COL_INSTANCE_VISIBILITY, FALSE,
+ SLR_MODEL_COL_VARIABLE_VISIBILITY, TRUE,
+ SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY, FALSE
+ -1);
+ g_string_free(tmp_str, TRUE);
+ }
+ g_list_free(vars);
+
+ _consume_excess_rows(model->real, visible_variable_index, &inst_tree_iter, &var_tree_iter);
+ }
+ }
+
+ // if there are more instance iters, remove
+ _consume_excess_rows(model->real, instance_index, &sx_tree_iter, &inst_tree_iter);
+ }
+ }
+ _consume_excess_rows(model->real, instances_index, NULL, &sx_tree_iter);
+}
+
+GncSxInstanceModel*
+gnc_sx_slr_tree_model_adapter_get_instance_model(GncSxSlrTreeModelAdapter *slr_model)
+{
+ return slr_model->instances;
+}
+
+GncSxInstances*
+gnc_sx_slr_tree_model_adapter_get_sx_instances(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter)
+{
+ return _gnc_sx_slr_tree_model_adapter_get_sx_instances(model, iter, TRUE);
+}
+
+static GncSxInstances*
+_gnc_sx_slr_tree_model_adapter_get_sx_instances(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter, gboolean check_depth)
+{
+ GtkTreePath *path;
+ gint *indices, index;
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), iter);
+ if (check_depth && gtk_tree_path_get_depth(path) != 1)
+ {
+ gtk_tree_path_free(path);
+ return NULL;
+ }
+ indices = gtk_tree_path_get_indices(path);
+ index = indices[0];
+ gtk_tree_path_free(path);
+
+ return (GncSxInstances*)g_list_nth_data(model->instances->sx_instance_list, index);
+}
+
+GncSxInstance*
+gnc_sx_slr_model_get_instance(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter)
+{
+ return _gnc_sx_slr_model_get_instance(model, iter, TRUE);
+}
+
+static GncSxInstance*
+_gnc_sx_slr_model_get_instance(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter, gboolean check_depth)
+{
+ GtkTreePath *path;
+ gint *indices, instances_index, instance_index;
+ GncSxInstances *instances;
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), iter);
+ if (check_depth && gtk_tree_path_get_depth(path) != 2)
+ {
+ gtk_tree_path_free(path);
+ return NULL;
+ }
+ indices = gtk_tree_path_get_indices(path);
+ instances_index = indices[0];
+ instance_index = indices[1];
+ gtk_tree_path_free(path);
+
+ instances = (GncSxInstances*)g_list_nth_data(model->instances->sx_instance_list, instances_index);
+ if (instance_index < 0 || instance_index >= g_list_length(instances->list))
+ {
+ return NULL;
+ }
+
+ return (GncSxInstance*)g_list_nth_data(instances->list, instance_index);
+}
+
+gboolean
+gnc_sx_slr_model_get_instance_and_variable(GncSxSlrTreeModelAdapter *model, GtkTreeIter *iter, GncSxInstance **instance_loc, GncSxVariable **var_loc)
+{
+ GtkTreePath *path;
+ gint *indices, variable_index;
+ GncSxInstance *instance;
+ GList *variables;
+
+ instance = _gnc_sx_slr_model_get_instance(model, iter, FALSE);
+ if (instance == NULL)
+ {
+ return FALSE;
+ }
+ variables = gnc_sx_instance_get_variables(instance);
+
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), iter);
+ if (gtk_tree_path_get_depth(path) != 3)
+ {
+ gtk_tree_path_free(path);
+ return FALSE;
+ }
+ indices = gtk_tree_path_get_indices(path);
+ variable_index = indices[2];
+ gtk_tree_path_free(path);
+
+ if (variable_index < 0 || variable_index >= g_list_length(variables))
+ {
+ g_list_free(variables);
+ return FALSE;
+ }
+
+ if (instance_loc != NULL)
+ {
+ *instance_loc = instance;
+ }
+
+ if (var_loc != NULL)
+ {
+ // *var_loc = (GncSxVariable*)g_list_nth_data(variables, variable_index);
+ GList *list_iter = variables;
+ for (; list_iter != NULL; list_iter = list_iter->next)
+ {
+ GncSxVariable *var = (GncSxVariable*)list_iter->data;
+ if (!var->editable)
+ continue;
+ if (variable_index-- == 0)
+ {
+ *var_loc = var;
+ break;
+ }
+ }
+ }
+
+ g_list_free(variables);
+ return TRUE;
+}
+
+void
+gnc_sx_slr_model_change_instance_state(GncSxSlrTreeModelAdapter *model, GncSxInstance *instance, GncSxInstanceState new_state)
+{
+ // @fixme: pop this out a level.
+ gnc_sx_instance_model_change_instance_state(model->instances, instance, new_state);
+}
+
+/**
+ * Special-case list indexing that only refers to "editable" variables. :(
+ **/
+static gint
+_variable_list_index(GList *variables, GncSxVariable *variable)
+{
+ gint index = 0;
+ for (; variables != NULL; variables = variables->next)
+ {
+ GncSxVariable *var = (GncSxVariable*)variables->data;
+ if (!var->editable)
+ continue;
+ if (variable == var)
+ return index;
+ index++;
+ }
+ return -1;
+}
+
+static GtkTreePath*
+_get_path_for_variable(GncSxSlrTreeModelAdapter *model, GncSxInstance *instance, GncSxVariable *variable)
+{
+ GList *variables;
+ int indices[3];
+ GtkTreePath *path;
+
+ indices[0] = g_list_index(model->instances->sx_instance_list, instance->parent);
+ if (indices[0] == -1)
+ return NULL;
+ indices[1] = g_list_index(instance->parent->list, instance);
+ if (indices[1] == -1)
+ return NULL;
+ variables = gnc_sx_instance_get_variables(instance);
+ indices[2] = _variable_list_index(variables, variable);
+ g_list_free(variables);
+ if (indices[2] == -1)
+ return NULL;
+ path = gtk_tree_path_new_from_indices(indices[0], indices[1], indices[2], -1);
+ return path;
+}
+
+void
+gnc_sx_slr_model_change_variable(GncSxSlrTreeModelAdapter *model, GncSxInstance *instance, GncSxVariable *variable, gnc_numeric *new_value)
+{
+ gnc_sx_instance_model_set_variable(model->instances, instance, variable, new_value);
+}
+
+static void
+gsslrtma_added_cb(GncSxInstanceModel *instances, SchedXaction *added_sx, gpointer user_data)
+{
+ GncSxSlrTreeModelAdapter *model = GNC_SX_SLR_TREE_MODEL_ADAPTER(user_data);
+ // this is wasteful, but fine.
+ gsslrtma_populate_tree_store(model);
+}
+
+static void
+gsslrtma_updated_cb(GncSxInstanceModel *instances, SchedXaction *updated_sx, gpointer user_data)
+{
+ GncSxSlrTreeModelAdapter *model = GNC_SX_SLR_TREE_MODEL_ADAPTER(user_data);
+ gnc_sx_instance_model_update_sx_instances(instances, updated_sx);
+ gsslrtma_populate_tree_store(model);
+}
+
+static void
+gsslrtma_removing_cb(GncSxInstanceModel *instances, SchedXaction *to_remove_sx, gpointer user_data)
+{
+ GncSxSlrTreeModelAdapter *model = GNC_SX_SLR_TREE_MODEL_ADAPTER(user_data);
+ GtkTreeIter tree_iter;
+ GList *iter;
+ int index = 0;
+ // get index, create path, remove
+ for (iter = instances->sx_instance_list; iter != NULL; iter = iter->next, index++)
+ {
+ GncSxInstances *instances = (GncSxInstances*)iter->data;
+ if (instances->sx == to_remove_sx)
+ break;
+ }
+ if (iter == NULL)
+ return; // couldn't find sx in our model, which is weird.
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(model->real), &tree_iter, NULL, index))
+ return; // perr(couldn't get something that should exist.
+ gtk_tree_store_remove(model->real, &tree_iter);
+
+ gnc_sx_instance_model_remove_sx_instances(instances, to_remove_sx);
+}
+
+static void
+gnc_sx_slr_tree_model_adapter_dispose(GObject *obj)
+{
+ GncSxSlrTreeModelAdapter *adapter;
+ g_return_if_fail(obj != NULL);
+ adapter = GNC_SX_SLR_TREE_MODEL_ADAPTER(obj);
+ g_return_if_fail(!adapter->disposed);
+ adapter->disposed = TRUE;
+
+ g_object_unref(G_OBJECT(adapter->instances));
+ adapter->instances = NULL;
+ g_object_unref(G_OBJECT(adapter->real));
+ adapter->real = NULL;
+
+ G_OBJECT_CLASS(parent_class)->dispose(obj);
+}
+
+static void
+gnc_sx_slr_tree_model_adapter_finalize(GObject *obj)
+{
+ g_return_if_fail(obj != NULL);
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+GncSxSlrTreeModelAdapter*
+gnc_sx_slr_tree_model_adapter_new(GncSxInstanceModel *instances)
+{
+ GncSxSlrTreeModelAdapter *rtn;
+ rtn = GNC_SX_SLR_TREE_MODEL_ADAPTER(g_object_new(GNC_TYPE_SX_SLR_TREE_MODEL_ADAPTER, NULL));
+ rtn->instances = instances;
+ g_object_ref(G_OBJECT(rtn->instances));
+ gsslrtma_populate_tree_store(rtn);
+ g_signal_connect(G_OBJECT(rtn->instances), "added", (GCallback)gsslrtma_added_cb, (gpointer)rtn);
+ rtn->updated_cb_id = g_signal_connect(G_OBJECT(rtn->instances), "updated", (GCallback)gsslrtma_updated_cb, (gpointer)rtn);
+ g_signal_connect(G_OBJECT(rtn->instances), "removing", (GCallback)gsslrtma_removing_cb, (gpointer)rtn);
+ return rtn;
+}
+
+void
+gnc_sx_sxsincelast_book_opened(void)
+{
+ GncSxInstanceModel *inst_model;
+ GncSxSummary summary;
+
+ if (!gnc_gconf_get_bool(GCONF_SECTION, "show_at_file_open", NULL))
+ return;
+
+ inst_model = gnc_sx_get_current_instances();
+ gnc_sx_instance_model_summarize(inst_model, &summary);
+ gnc_sx_summary_print(&summary);
+ gnc_sx_instance_model_effect_change(inst_model, TRUE, NULL, NULL);
+
+ if (summary.need_dialog)
+ {
+ gnc_ui_sx_since_last_run_dialog(inst_model);
+ }
+ else
+ {
+ if (summary.num_auto_create_no_notify_instances != 0)
+ {
+ gnc_info_dialog
+ (NULL,
+ ngettext
+ ("There are no Scheduled Transactions to be entered at this time. "
+ "(%d transaction automatically created)",
+ "There are no Scheduled Transactions to be entered at this time. "
+ "(%d transactions automatically created)",
+ summary.num_auto_create_no_notify_instances),
+ summary.num_auto_create_no_notify_instances);
+ }
+ }
+ g_object_unref(G_OBJECT(inst_model));
+}
+
+void
+gnc_ui_sxsincelast_dialog_create(void)
+{
+ GncSxInstanceModel *model = gnc_sx_get_current_instances();
+ gnc_sx_instance_model_effect_change(model, TRUE, NULL, NULL);
+ gnc_ui_sx_since_last_run_dialog(model);
+ g_object_unref(G_OBJECT(model));
+}
+
+static void
+instance_state_changed_cb(GtkCellRendererText *cell,
+ const gchar *path,
+ const gchar *value,
+ GncSxSinceLastRunDialog *dialog)
+{
+ GtkTreeIter tree_iter;
+ GncSxInstance *inst;
+ int i;
+ GncSxInstanceState new_state;
+
+ for (i = 0; i < SX_INSTANCE_STATE_CREATED; i++)
+ {
+ if (strcmp(value, gnc_sx_instance_state_names[i]) == 0)
+ break;
+ }
+ if (i == SX_INSTANCE_STATE_CREATED)
+ {
+ printf("unknown value [%s]\n", value);
+ return;
+ }
+ new_state = i;
+
+ if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(dialog->editing_model), &tree_iter, path))
+ {
+ printf("unknown path [%s]\n", path);
+ return;
+ }
+
+ inst = gnc_sx_slr_model_get_instance(dialog->editing_model, &tree_iter);
+ if (inst == NULL)
+ {
+ printf("invalid path [%s]\n", path);
+ return;
+ }
+
+ gnc_sx_slr_model_change_instance_state(dialog->editing_model, inst, new_state);
+}
+
+static void
+variable_value_changed_cb(GtkCellRendererText *cell,
+ const gchar *path,
+ const gchar *value,
+ GncSxSinceLastRunDialog *dialog)
+{
+ GncSxVariable *var;
+ GncSxInstance *inst;
+ GtkTreeIter tree_iter;
+ gnc_numeric parsed_num;
+ char *endStr = NULL;
+
+ printf("variable to [%s] at path [%s]\n", value, path);
+ if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(dialog->editing_model), &tree_iter, path))
+ {
+ printf("invalid path [%s]\n", path);
+ return;
+ }
+
+ if (!gnc_sx_slr_model_get_instance_and_variable(dialog->editing_model, &tree_iter, &inst, &var))
+ {
+ printf("path [%s] doesn't correspond to a valid variable\n", path);
+ return;
+ }
+
+ if (!xaccParseAmount(value, TRUE, &parsed_num, &endStr)
+ || gnc_numeric_check(parsed_num) != GNC_ERROR_OK)
+ {
+ printf("@@fixme: better parse error handling\n");
+ // @fixme: set location (back) to "(need value)"
+ return;
+ }
+ gnc_sx_slr_model_change_variable(dialog->editing_model, inst, var, &parsed_num);
+}
+
+GncSxSinceLastRunDialog*
+gnc_ui_sx_since_last_run_dialog(GncSxInstanceModel *sx_instances)
+{
+ GncSxSinceLastRunDialog *dialog;
+ GladeXML *glade;
+
+ dialog = g_new0(GncSxSinceLastRunDialog, 1);
+ glade = gnc_glade_xml_new("sched-xact.glade", "since-last-run-dialog");
+ dialog->dialog = glade_xml_get_widget(glade, "since-last-run-dialog");
+
+ dialog->editing_model = gnc_sx_slr_tree_model_adapter_new(sx_instances);
+ // gobject-2.10: g_object_ref_sink(G_OBJECT(dialog->editing_model));
+ g_object_ref(G_OBJECT(dialog->editing_model));
+ gtk_object_sink(GTK_OBJECT(dialog->editing_model));
+
+ {
+ GtkPaned *paned;
+
+ paned = GTK_PANED(glade_xml_get_widget(glade, "paned"));
+ gtk_paned_set_position(paned, 240);
+ }
+
+ dialog->review_created_txns_toggle = GTK_TOGGLE_BUTTON(glade_xml_get_widget(glade, "review_txn_toggle"));
+
+ {
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *col;
+
+ dialog->instance_view = GTK_TREE_VIEW(glade_xml_get_widget(glade, "instance_view"));
+ gtk_tree_view_set_model(dialog->instance_view, GTK_TREE_MODEL(dialog->editing_model));
+
+ renderer = gtk_cell_renderer_text_new();
+ col = gtk_tree_view_column_new_with_attributes("SX, Instance, Variable", renderer,
+ "text", SLR_MODEL_COL_NAME,
+ NULL);
+ gtk_tree_view_append_column(dialog->instance_view, col);
+
+ renderer = gtk_cell_renderer_combo_new();
+ g_object_set(G_OBJECT(renderer),
+ "model", gnc_sx_get_slr_state_model(),
+ "text-column", 0,
+ "has-entry", FALSE,
+ "editable", TRUE,
+ NULL);
+ g_signal_connect(G_OBJECT(renderer),
+ "edited",
+ G_CALLBACK(instance_state_changed_cb),
+ dialog);
+ col = gtk_tree_view_column_new_with_attributes("Instance State", renderer,
+ "text", SLR_MODEL_COL_INSTANCE_STATE,
+ "visible", SLR_MODEL_COL_INSTANCE_VISIBILITY,
+ // you might think only "sensitive" is required to
+ // control the ability of the combo box to select
+ // a new state, but you'd be wrong.
+ "editable", SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY,
+ "sensitive", SLR_MODEL_COL_INSTANCE_STATE_SENSITIVITY,
+ NULL);
+ gtk_tree_view_append_column(dialog->instance_view, col);
+
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer),
+ "editable", TRUE,
+ NULL);
+ g_signal_connect(G_OBJECT(renderer),
+ "edited",
+ G_CALLBACK(variable_value_changed_cb),
+ dialog);
+ col = gtk_tree_view_column_new_with_attributes("Variable Value", renderer,
+ "text", SLR_MODEL_COL_VARAIBLE_VALUE,
+ "visible", SLR_MODEL_COL_VARIABLE_VISIBILITY,
+ NULL);
+ gtk_tree_view_append_column(dialog->instance_view, col);
+
+ gtk_tree_view_expand_all(dialog->instance_view);
+ }
+
+ g_signal_connect(G_OBJECT(dialog->dialog), "response", G_CALLBACK(dialog_response_cb), dialog);
+
+ gtk_widget_show_all(dialog->dialog);
+
+ return dialog;
+}
+
+static void
+_show_created_transactions(GncSxSinceLastRunDialog *app_dialog, GList *created_txn_guids)
+{
+ GNCLedgerDisplay *ledger;
+ GncPluginPage *page;
+ Query *book_query, *guid_query, *query;
+ GList *guid_iter;
+
+ book_query = xaccMallocQuery();
+ guid_query = xaccMallocQuery();
+ xaccQuerySetBook(book_query, gnc_get_current_book());
+ for (guid_iter = created_txn_guids; guid_iter != NULL; guid_iter = guid_iter->next)
+ {
+ xaccQueryAddGUIDMatch(guid_query, (GUID*)guid_iter->data, GNC_ID_TRANS, QUERY_OR);
+ }
+ query = xaccQueryMerge(book_query, guid_query, QUERY_AND);
+
+ // inspired by dialog-find-transactions:do_find_cb:
+ ledger = gnc_ledger_display_query(query, SEARCH_LEDGER, REG_STYLE_JOURNAL);
+ gnc_ledger_display_refresh(ledger);
+ page = gnc_plugin_page_register_new_ledger(ledger);
+ g_object_set(G_OBJECT(page), "page-name", _("Created Transactions"), NULL);
+ gnc_main_window_open_page(NULL, page);
+
+ xaccFreeQuery(query);
+ xaccFreeQuery(book_query);
+ xaccFreeQuery(guid_query);
+}
+
+static GList*
+gnc_sx_slr_model_check_variables(GncSxSlrTreeModelAdapter *editing_model)
+{
+ return gnc_sx_instance_model_check_variables(editing_model->instances);
+}
+
+static void
+dialog_response_cb(GtkDialog *dialog, gint response_id, GncSxSinceLastRunDialog *app_dialog)
+{
+ GList *created_txns = NULL;
+ switch (response_id)
+ {
+ case GTK_RESPONSE_OK:
+ // @@fixme validate current state(GError *errs);
+ // - instance state constraints
+ // - required variable binding
+ // - ability to create transactions
+ {
+ GList *unbound_variables;
+ unbound_variables = gnc_sx_slr_model_check_variables(app_dialog->editing_model);
+ printf("%d variables unbound\n", g_list_length(unbound_variables));
+ if (g_list_length(unbound_variables) > 0)
+ {
+ // focus first variable
+ GncSxVariableNeeded *first_unbound;
+ GtkTreePath *variable_path;
+ GtkTreeViewColumn *variable_col;
+ gint variable_view_column = 2;
+ gboolean start_editing = TRUE;
+
+ first_unbound = (GncSxVariableNeeded*)unbound_variables->data;
+ variable_path = _get_path_for_variable(app_dialog->editing_model, first_unbound->instance, first_unbound->variable);
+ variable_col = gtk_tree_view_get_column(app_dialog->instance_view, variable_view_column);
+
+ gtk_tree_view_set_cursor(app_dialog->instance_view, variable_path, variable_col, start_editing);
+
+ gtk_tree_path_free(variable_path);
+ g_list_foreach(unbound_variables, (GFunc)g_free, NULL);
+ g_list_free(unbound_variables);
+ return;
+ }
+ }
+ gnc_suspend_gui_refresh();
+ gnc_sx_slr_model_effect_change(app_dialog->editing_model, FALSE, &created_txns, NULL);
+ gnc_resume_gui_refresh();
+ if (gtk_toggle_button_get_active(app_dialog->review_created_txns_toggle)
+ && g_list_length(created_txns) > 0)
+ {
+ _show_created_transactions(app_dialog, created_txns);
+ }
+ g_list_free(created_txns);
+ created_txns = NULL;
+ /* FALLTHROUGH */
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ g_object_unref(G_OBJECT(app_dialog->editing_model));
+ app_dialog->editing_model = NULL;
+ break;
+ default:
+ printf("unknown response id [%d]\n", response_id);
+ g_assert_not_reached();
+ break;
+ }
+}
+
+/**
+ * @param auto_create_only Will only affect auto-create transactions; the
+ * rest of the state will be left alone.
+ **/
+void
+gnc_sx_slr_model_effect_change(GncSxSlrTreeModelAdapter *model,
+ gboolean auto_create_only,
+ GList **created_transaction_guids,
+ GList **creation_errors)
+{
+ g_signal_handler_block(model->instances, model->updated_cb_id);
+ gnc_sx_instance_model_effect_change(model->instances, auto_create_only, created_transaction_guids, creation_errors);
+ g_signal_handler_unblock(model->instances, model->updated_cb_id);
+}
+
Copied: gnucash/trunk/src/gnome/dialog-sx-since-last-run.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/dialog-sx-since-last-run.h)
Deleted: gnucash/trunk/src/gnome/dialog-sxsincelast.c
===================================================================
--- gnucash/trunk/src/gnome/dialog-sxsincelast.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/dialog-sxsincelast.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,4030 +0,0 @@
-/********************************************************************\
- * dialog-sxsincelast.c - "since last run" dialog. *
- * Copyright (c) 2001,2002 Joshua Sled <jsled at asynchronous.org> *
- * *
- * 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 *
-\********************************************************************/
-
-/**
- * . Page 1: reminders list
- * . backed by: sxsld->reminderList
- * . Page 2: auto-create notify ledger
- * . backed by: sxsld->autoCreateList
- * . Page 3: to-create variable bindings
- * . backed by: sxsld->toCreateData [s/Data/List/]
- * . Page 4: created ledger
- * . backed by: sxsld->createdList
- * . Page 5: obsolete list
- * . backed by: sxsld->toRemoveList
- *
- * Detail regarding 'back' processing support.
- * . reminders
- * . selected
- * . <standard policy>
- * . unselected
- * . if auto-created : delete
- * . if to-create : remove
- * . auto-create : display
- * . to-create variable bindings
- * . if bindings changed : reeval/fill credit/debit cells
- * . if made incomplete : delete transaction
- * . created : display
- * . obsolete : select status [easy]
- **/
-
-#include "config.h"
-
-#include <gnome.h>
-#include <glib.h>
-#include <glib/gi18n.h>
-#include "glib-compat.h"
-#include <limits.h>
-
-#include "Account.h"
-#include "Group.h"
-#include "Query.h"
-#include "QueryNew.h"
-#include "SchedXaction.h"
-#include "Transaction.h"
-#include "Scrub.h"
-#include "SX-book.h"
-#include "SX-book-p.h"
-#include "dialog-utils.h"
-#include "finvar.h"
-#include "gnc-date.h"
-#include "gnc-component-manager.h"
-#include "gnc-engine.h"
-#include "gnc-exp-parser.h"
-#include "gnc-embedded-window.h"
-#include "gnc-gconf-utils.h"
-#include "gnc-main-window.h"
-#include "gnc-numeric.h"
-#include "gnc-plugin-page.h"
-#include "gnc-plugin-page-register.h"
-#include "gnc-ui-util.h"
-#include "gnc-ui.h"
-#include "gnc-gui-query.h"
-#include "split-register.h"
-#include "gnc-ledger-display.h"
-#include "gnucash-sheet.h"
-#include "gnc-split-reg.h"
-
-#include "dialog-sxsincelast.h"
-#include "dialog-scheduledxaction.h"
-
-#ifdef HAVE_LANGINFO_D_FMT
-#include <langinfo.h>
-#endif
-
-#define DIALOG_SXSINCELAST_CM_CLASS "dialog-sxsincelast"
-#define DIALOG_SXSINCELAST_REMIND_CM_CLASS "dialog-sxsincelast-remind"
-#define DIALOG_SXSINCELAST_OBSOLETE_CM_CLASS "dialog-sxsincelast-obsolete"
-
-#define DIALOG_SXSINCELAST_GLADE_NAME "Since Last Run Druid"
-#define SXSLD_DRUID_GLADE_NAME "sincelast_druid"
-#define SXSLD_WIN_PREFIX "sx_sincelast_win"
-#define GCONF_SECTION "dialogs/scheduled_trans/since_last_run"
-
-#define SINCELAST_DRUID "sincelast_druid"
-#define WHAT_TO_DO_PG "what_to_do"
-#define REMINDERS_PG "reminders_page"
-#define AUTO_CREATE_NOTIFY_PG "auto_create_notify_page"
-#define TO_CREATE_PG "to_create_page"
-#define CREATED_PG "created_page"
-#define OBSOLETE_PG "obsolete_page"
-#define COMMIT_PG "commit_page"
-
-#define SX_OBSOLETE_CLIST "sx_obsolete_clist"
-#define TO_CREATE_LIST "to_create_list"
-#define REMINDER_LIST "reminders_list"
-#define SX_GLADE_FILE "sched-xact.glade"
-
-#define TO_CREATE_STATUS "to_create_status"
-
-#define SELECT_ALL_BUTTON "select_all_button"
-#define UNSELECT_ALL_BUTTON "unselect_all_button"
-#define OK_BUTTON "ok_button"
-#define CANCEL_BUTTON "cancel_button"
-#define VARIABLE_TABLE "variables_table"
-#define AUTO_CREATE_VBOX "ac_vbox"
-#define TO_CREATE_TXN_VBOX "to_create_txn_vbox"
-#define CREATED_VBOX "created_vbox"
-#define WHAT_TO_DO_VBOX "what_to_do_vbox"
-#define WHAT_TO_DO_PROGRESS "creation_progress"
-#define SX_DISPOSITION_OPT "disposition_opt"
-
-#define TO_CREATE_LIST_WIDTH 2
-#define REMINDER_LIST_WIDTH 3
-#define SX_OBSOLETE_CLIST_WIDTH 3
-
-#define COERCE_VOID_TO_GBOOLEAN(x) ((gboolean)(*#x))
-
-#define IGNORE_TEXT "Ignored"
-#define POSTPONE_TEXT "Postponed"
-#define READY_TEXT "Ready to create"
-#define NEEDS_BINDINGS_TEXT "Needs values for variables"
-
-static QofLogModule log_module = GNC_MOD_SX;
-
-/**
- * Directions for {forward,back}-page determining.
- * @see gnc_sxsld_get_appropriate_page
- **/
-typedef enum {
- FORWARD, BACK
-} Direction;
-
-/**
- * The states a to-be-created SX can be in...
- * SX_TO_CREATE : The SX is ready to be created, depending on variable-binding
- * requirements.
- * SX_IGNORE : Drop the SX on the floor forever.
- * SX_POSTPONE : Bring this SX up in the future, but we're not going to
- * create it right now.
- * SX_[MAX_STATE] : The maximum real value.
- * SX_UNDEF : Only used for prevState, to indicate that we haven't
- * processed this instance, yet.
- **/
-typedef enum {
- SX_TO_CREATE,
- SX_IGNORE,
- SX_POSTPONE,
- SX_MAX_STATE,
- SX_UNDEF
-} ToCreateState;
-
-typedef struct toCreateTuple_ {
- SchedXaction *sx;
- GList /* <toCreateInstance*> */ *instanceList;
-} toCreateTuple;
-
-typedef struct toCreateInstance_ {
- GDate *date;
- GHashTable *varBindings;
- void *sxStateData;
- GtkCTreeNode *node;
- toCreateTuple *parentTCT;
- /* A list of the GUIDs of transactions generated from this TCI [if
- * any]; this will always be a subset of the
- * sxsld->createdTxnGUIDList. */
- GList /* <GUID*> */ *createdTxnGUIDs;
- gboolean dirty;
- /** How this was, originally -- for revert processing. **/
- ToCreateState origState;
- /** How the user would currently like to process this instance
- * [within the druid]. */
- ToCreateState state;
- /** How we've previously processed this instance [within the druid]. */
- ToCreateState prevState;
-} toCreateInstance;
-
-/**
- * A tuple of an SX and any upcoming reminders.
- **/
-typedef struct reminderTuple_ {
- SchedXaction *sx;
- GList /* <reminderInstanceTuple*> */ *instanceList;
-} reminderTuple;
-
-/**
- * An reminder instance of the containing SX.
- **/
-typedef struct reminderInstanceTuple_ {
- GDate *endDate;
- GDate *occurDate;
- void *sxStateData;
- gboolean isSelected;
- reminderTuple *parentRT;
- toCreateInstance *resultantTCI;
-} reminderInstanceTuple;
-
-typedef struct toDeleteTuple_ {
- SchedXaction *sx;
- GDate *endDate;
- gboolean isSelected;
-} toDeleteTuple;
-
-typedef struct creation_helper_userdata_ {
- /* the to-create tuple */
- toCreateInstance *tci;
- /* a pointer to a GList to append the GUIDs of newly-created
- * Transactions to, or NULL */
- GList **createdGUIDs;
- /* a pointer to a GList<GString*> of error-messages encountered while
- * creating the transactions. **/
- GList **creation_errors;
-} createData;
-
-/**
- * The since-last-run dialog is a Gnome Druid which steps through the various
- * parts of scheduled transaction since-last-run processing; these parts are:
- *
- * 1. Display and select SX reminders for creation
- * 2. Show/allow editing of auto-created + notification-request SXes
- * 3. Show to-create SXes, allowing variable binding
- * 4. Show created SXes, allowing editing
- * 5. Allow deletion of any obsolete SXes
- *
- * Pages which aren't relevant are skipped; this is handled in the 'prep'
- * signal handler: e.g., a since-last dialog with only obsolete SXes would go
- * through the 'prep' methods of all it's pages to reach the Obsolete page.
- **/
-typedef struct _sxSinceLastData {
- GtkWidget *sincelast_window;
- GnomeDruid *sincelast_druid;
- GladeXML *gxml;
-
- GtkProgressBar *prog;
- GtkStatusbar *toCreateFormula;
- guint formulaCtxId;
- GtkStatusbar *toCreateStatus;
- guint statusCtxId;
-
- /* The currently-selected to-create instance. */
- toCreateInstance *curSelTCI;
-
- /* Multi-stage processing-related stuff... */
- GList /* <toCreateTuple*> */ *autoCreateList;
- GList /* <toCreateTuple*> */ *toCreateList;
- GList /* <reminderTuple*> */ *reminderList;
- GList /* <toDeleteTuple*> */ *toRemoveList;
-
- /********** "Cancel"-related stuff... **********/
-
- /** A HashTable of SX mapped to initial temporal data. */
- GHashTable /* <SchedXaction*,void*> */ *sxInitStates;
-
- /** The list of the GUIDs of _all_ transactions we've created. */
- GList /* <GUID*> */ *createdTxnGUIDList;
-
- /* The count of selected reminders. */
- gint remindSelCount;
-
- /* The count of auto-created transactions. */
- gint autoCreatedCount;
-
- GncEmbeddedWindow *ac_window;
- GncPluginPage *ac_register;
- GNCLedgerDisplay *ac_ledger;
-
- GncEmbeddedWindow *created_window;
- GncPluginPage *created_register;
- GNCLedgerDisplay *created_ledger;
-
- GncEmbeddedWindow *to_create_window;
- GncPluginPage *to_create_register;
- GNCLedgerDisplay *to_create_ledger;
-
-} sxSinceLastData;
-
-static void sxsincelast_init( sxSinceLastData *sxsld );
-static void create_autoCreate_ledger( sxSinceLastData *sxsld );
-static void create_created_ledger( sxSinceLastData *sxsld );
-static void create_to_create_ledger( sxSinceLastData *sxsld );
-static void gnc_sxsld_commit_ledgers( sxSinceLastData *sxsld );
-
-#if 0
-static void sxsld_jump_to_real_txn( GtkAction *action, sxSinceLastData *sxsld );
-#endif
-
-static gint sxsincelast_populate( sxSinceLastData *sxsld );
-static void sxsincelast_druid_cancelled( GnomeDruid *druid, gpointer ud );
-static void sxsincelast_close_handler( gpointer ud );
-
-static GnomeDruidPage* gnc_sxsld_get_appropriate_page( sxSinceLastData *sxsdl,
- GnomeDruidPage *from,
- Direction dir );
-static gboolean gnc_sxsld_wtd_appr( sxSinceLastData *sxsld );
-static gboolean gnc_sxsld_remind_appr( sxSinceLastData *sxsld );
-static gboolean gnc_sxsld_tocreate_appr( sxSinceLastData *sxsld );
-static gboolean gnc_sxsld_autocreate_appr( sxSinceLastData *sxsld );
-static gboolean gnc_sxsld_created_appr( sxSinceLastData *sxsld );
-static gboolean gnc_sxsld_obsolete_appr( sxSinceLastData *sxsld );
-static gboolean gnc_sxsld_commit_appr( sxSinceLastData *sxsld );
-
-static void sxsincelast_entry_changed( GtkEditable *e, gpointer ud );
-static void sxsincelast_destroy( GtkObject *o, gpointer ud );
-static void sxsincelast_save_size( sxSinceLastData *sxsld );
-static void create_transactions_on(SchedXaction *sx,
- GDate *gd,
- toCreateInstance *tci,
- GList **createdGUIDs,
- GList **creation_errors);
-static gint create_each_transaction_helper( Transaction *t, void *d );
-/* External for what reason ... ? */
-void sxsl_get_sx_vars( SchedXaction *sx, GHashTable *varHash );
-static void hash_to_sorted_list( GHashTable *hashTable, GList **gl );
-static void andequal_numerics_set( gpointer key,
- gpointer value,
- gpointer data );
-/* External for bad reasons, I think...? */
-void print_vars_helper( gpointer key,
- gpointer value,
- gpointer user_data );
-static void clean_sincelast_data( sxSinceLastData *sxsld );
-static void clean_variable_table( sxSinceLastData *sxsld );
-
-static void process_auto_create_list(GList *, sxSinceLastData *sxsld, GList **creation_errors);
-static void add_to_create_list_to_gui( GList *, sxSinceLastData *sxsld );
-static void add_reminders_to_gui( GList *, sxSinceLastData *sxsld );
-static void add_dead_list_to_gui( GList *, sxSinceLastData *sxsld );
-static void processSelectedReminderList( GList *, sxSinceLastData * );
-
-static void sxsincelast_tc_row_sel( GtkCTree *ct,
- GList *nodelist,
- gint column,
- gpointer user_data);
-
-static void sxsincelast_tc_row_unsel( GtkCTree *ct,
- GList *nodelist,
- gint column,
- gpointer user_data);
-
-static void sxsld_remind_row_toggle( GtkCTree *ct, GList *node,
- gint column, gpointer user_data );
-static void sxsld_obsolete_row_toggle( GtkCList *cl, gint row, gint col,
- GdkEventButton *event, gpointer ud );
-
-static void sxsld_disposition_changed( GtkMenuShell *b, gpointer d );
-static void sxsld_set_sensitive_tci_controls( sxSinceLastData *sxsld,
- gboolean sensitive );
-
-static void gnc_sxsld_revert_reminders( sxSinceLastData *sxsld,
- GList *toRevertList );
-static gboolean processed_valid_reminders_listP( sxSinceLastData *sxsld );
-static void create_bad_reminders_msg( gpointer data, gpointer ud );
-static gboolean inform_or_add( sxSinceLastData *sxsld, reminderTuple *rt, gboolean okFlag,
- GList *badList, GList **goodList );
-
-static void sx_obsolete_select_all_clicked( GtkButton *button,
- gpointer user_data );
-static void sx_obsolete_unselect_all_clicked( GtkButton *button,
- gpointer user_data );
-
-static void gnc_sxsld_free_tci( toCreateInstance *tci );
-static void gnc_sxsld_free_toCreateTuple_list( GList *l );
-static void gnc_sxsld_free_sxState( gpointer key,
- gpointer value,
- gpointer userdata );
-static void gnc_sxsld_free_entry_numeric( GObject *o, gpointer ud );
-
-static gint sxsld_process_to_create_instance(sxSinceLastData *sxsld,
- toCreateInstance *tci,
- GList **creation_errors);
-static void sxsld_revert_to_create_txns( sxSinceLastData *sxsld,
- toCreateInstance *tci );
-static gint sxsld_create_to_create_txns(sxSinceLastData *sxsld,
- toCreateInstance *tci,
- GList **creation_errors);
-static gint sxsld_get_future_created_txn_count( sxSinceLastData *sxsld );
-static void creation_errors_dialog(GList *creation_errors);
-static void creation_errors_free(GList *creation_errors);
-
-static GtkActionEntry gnc_sxsld_menu_entries [] =
-{
- /* Toplevel */
- { "EditAction", NULL, N_("_Edit"), NULL, NULL, NULL },
- { "TransactionAction", NULL, N_("_Transaction"), NULL, NULL, NULL },
- { "ViewAction", NULL, N_("_View"), NULL, NULL, NULL },
- { "ActionsAction", NULL, N_("_Actions"), NULL, NULL, NULL },
-};
-static guint gnc_sxsld_menu_n_entries = G_N_ELEMENTS (gnc_sxsld_menu_entries);
-
-/**
- * Used to wrap for the book-open hook, where the book filename is given.
- **/
-void
-gnc_sx_sxsincelast_book_opened (void)
-{
- gint ret;
-
- if (!gnc_gconf_get_bool(GCONF_SECTION, "show_at_file_open", NULL))
- return;
-
- ret = gnc_ui_sxsincelast_dialog_create();
- if ( ret < 0 ) {
- gnc_info_dialog
- (NULL,
- ngettext
- ("There are no Scheduled Transactions to be entered at this time. "
- "(%d transaction automatically created)",
- "There are no Scheduled Transactions to be entered at this time. "
- "(%d transactions automatically created)",
- -(ret)),
- -(ret));
- }
-}
-
-
-static gboolean
-show_handler (const char *class, gint component_id,
- gpointer user_data, gpointer iter_data)
-{
- GtkWidget *window = user_data;
-
- if (!window)
- return(FALSE);
- gtk_window_present (GTK_WINDOW(window));
- return(TRUE);
-}
-
-/**
- * @return The magnitude of the return value is the number of auto-created,
- * no-notification scheduled transactions created. This value is positive if
- * there are additionally other SXes which need user interaction and the
- * Druid has been displayed, or negative if there are not, and no Druid
- * window was realized. In the case where there the dialog has been
- * displayed but no auto-create-no-notify transactions have been created,
- * INT_MAX [limits.h] is returned. 0 is treated as negative, with no
- * transactions created and no dialog displayed. The caller can use this
- * value as appropriate to inform the user.
- *
- * [e.g., for book-open-hook: do nothing; for menu-selection: display an info
- * dialog stating there's nothing to do.]
- **/
-gint
-gnc_ui_sxsincelast_dialog_create()
-{
- int autoCreateCount;
- sxSinceLastData *sxsld;
-
- if (gnc_forall_gui_components (DIALOG_SXSINCELAST_CM_CLASS,
- show_handler, NULL))
- return 0;
-
-
- sxsld = g_new0( sxSinceLastData, 1 );
-
- sxsld->toCreateList = sxsld->reminderList = sxsld->toRemoveList = NULL;
- sxsld->sxInitStates = g_hash_table_new( g_direct_hash, g_direct_equal );
-
- autoCreateCount = sxsincelast_populate( sxsld );
- if ( autoCreateCount <= 0 ) {
- g_free( sxsld );
- return autoCreateCount;
- }
-
- sxsld->gxml = gnc_glade_xml_new( SX_GLADE_FILE,
- DIALOG_SXSINCELAST_GLADE_NAME );
- sxsld->sincelast_window =
- glade_xml_get_widget( sxsld->gxml,
- DIALOG_SXSINCELAST_GLADE_NAME );
- sxsld->sincelast_druid =
- GNOME_DRUID( glade_xml_get_widget( sxsld->gxml,
- SXSLD_DRUID_GLADE_NAME ) );
- sxsincelast_init( sxsld );
- return autoCreateCount;
-}
-
-static void
-clist_set_all_cols_autoresize( GtkCList *cl, guint n_cols )
-{
- guint col;
- for( col = 0; col< n_cols; col++ ) {
- gtk_clist_set_column_auto_resize (cl, col, TRUE);
- }
- return;
-}
-
-typedef struct {
- char *name;
- char *signal;
- void (*handlerFn)();
-} widgetSignalHandlerTuple;
-
-typedef struct {
- char *pageName;
- void (*prepareHandlerFn)();
- gboolean (*backHandlerFn)();
- gboolean (*nextHandlerFn)();
- void (*finishHandlerFn)();
- gboolean (*cancelHandlerFn)();
-} druidSignalHandlerTuple;
-
-static void
-dialog_widgets_attach_handlers(GladeXML *dialog_xml,
- widgetSignalHandlerTuple *handler_info,
- sxSinceLastData *sxsld)
-{
- int i;
- GtkWidget *w;
-
- for (i = 0; handler_info[i].name != NULL; i++)
- {
- w = glade_xml_get_widget(dialog_xml, handler_info[i].name);
- g_signal_connect( G_OBJECT(w), handler_info[i].signal,
- G_CALLBACK(handler_info[i].handlerFn),
- sxsld);
- }
-}
-
-static void
-druid_pages_attach_handlers( GladeXML *dialog_xml,
- druidSignalHandlerTuple *handler_info,
- sxSinceLastData *sxsld )
-{
- int i;
- GtkWidget *w;
-
- for(i = 0; handler_info[i].pageName != NULL; i++)
- {
- w = glade_xml_get_widget(dialog_xml, handler_info[i].pageName);
- if ( handler_info[i].prepareHandlerFn ) {
- g_signal_connect( G_OBJECT(w), "prepare",
- G_CALLBACK(handler_info[i].
- prepareHandlerFn),
- sxsld);
- }
- if ( handler_info[i].backHandlerFn ) {
- g_signal_connect( G_OBJECT(w), "back",
- G_CALLBACK(handler_info[i].
- backHandlerFn),
- sxsld);
- }
- if ( handler_info[i].nextHandlerFn ) {
- g_signal_connect( G_OBJECT(w), "next",
- G_CALLBACK(handler_info[i].
- nextHandlerFn),
- sxsld);
- }
- if ( handler_info[i].finishHandlerFn ) {
- g_signal_connect( G_OBJECT(w), "finish",
- G_CALLBACK(handler_info[i].
- finishHandlerFn),
- sxsld);
- }
- if ( handler_info[i].cancelHandlerFn ) {
- g_signal_connect( G_OBJECT(w), "cancel",
- G_CALLBACK(handler_info[i].
- cancelHandlerFn),
- sxsld);
- }
- }
-}
-
-static void
-sxsincelast_druid_cancelled( GnomeDruid *druid, gpointer ud )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- gtk_widget_hide( sxsld->sincelast_window );
- sxsincelast_close_handler( sxsld );
-}
-
-/**
- * Using the specified direction, gets the next appropriate page. Returns
- * NULL if there is no approrpiate page to go to.
- **/
-static
-GnomeDruidPage*
-gnc_sxsld_get_appropriate_page( sxSinceLastData *sxsld,
- GnomeDruidPage *from,
- Direction dir )
-{
- static struct {
- gchar *pageName;
- gboolean (*pageAppropriate)( sxSinceLastData *sxsld );
- } pages[] = {
- { WHAT_TO_DO_PG, gnc_sxsld_wtd_appr },
- { REMINDERS_PG, gnc_sxsld_remind_appr },
- { AUTO_CREATE_NOTIFY_PG, gnc_sxsld_autocreate_appr },
- { TO_CREATE_PG, gnc_sxsld_tocreate_appr },
- { CREATED_PG, gnc_sxsld_created_appr },
- { OBSOLETE_PG, gnc_sxsld_obsolete_appr },
- { COMMIT_PG, gnc_sxsld_commit_appr },
- { NULL, NULL }
- };
- int modifier;
- int cur;
- GtkWidget *pg;
-
- pg = NULL;
- /* get the current page index via lame linear search. */
- for ( cur = 0; pages[cur].pageName != NULL; cur++ ) {
- pg = glade_xml_get_widget( sxsld->gxml, pages[cur].pageName );
- if ( GTK_WIDGET(from) == pg ) {
- break;
- }
- }
- g_assert( pages[cur].pageName != NULL );
-
- modifier = ( dir == FORWARD ? 1 : -1 );
- /* Find the approrpriate "next" page; start trying the first possible
- * "next" page. */
- cur += modifier;
- while ( cur >= 0
- && pages[cur].pageName != NULL
- && !(*pages[cur].pageAppropriate)( sxsld ) ) {
- cur += modifier;
- }
-
- if ( cur < 0
- || pages[cur].pageName == NULL ) {
- return NULL;
- }
- return GNOME_DRUID_PAGE( glade_xml_get_widget( sxsld->gxml,
- pages[cur].pageName ) );
-}
-
-static
-gboolean
-gnc_sxsld_wtd_appr( sxSinceLastData *sxsld )
-{
- /* It's never appropriate to return here. */
- return FALSE;
-}
-
-static
-gboolean
-gnc_sxsld_remind_appr( sxSinceLastData *sxsld )
-{
- return (g_list_length( sxsld->reminderList ) != 0);
-}
-
-static
-gboolean
-gnc_sxsld_tocreate_appr( sxSinceLastData *sxsld )
-{
- return (g_list_length( sxsld->toCreateList ) != 0);
-}
-
-static
-gboolean
-gnc_sxsld_autocreate_appr( sxSinceLastData *sxsld )
-{
- return (sxsld->autoCreatedCount > 0);
-}
-
-static
-gboolean
-gnc_sxsld_created_appr( sxSinceLastData *sxsld )
-{
- return ((g_list_length(sxsld->createdTxnGUIDList)
- - sxsld->autoCreatedCount) > 0);
-}
-
-static
-gboolean
-gnc_sxsld_obsolete_appr( sxSinceLastData *sxsld )
-{
- return (g_list_length( sxsld->toRemoveList ) != 0);
-}
-
-static
-gboolean
-gnc_sxsld_commit_appr( sxSinceLastData *sxsld )
-{
- /* Always show this page */
- return TRUE;
-}
-
-static
-gboolean
-gen_back( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GnomeDruidPage *gdp;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- if ( !(gdp = gnc_sxsld_get_appropriate_page( sxsld, druid_page, BACK )) ) {
- DEBUG( "No appropriate page to go to." );
- return TRUE;
- }
- gnome_druid_set_page( sxsld->sincelast_druid, gdp );
- return TRUE;
-}
-
-static
-gboolean
-gen_next( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GnomeDruidPage *gdp;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- if ( !(gdp = gnc_sxsld_get_appropriate_page( sxsld, druid_page, FORWARD )) ) {
- DEBUG( "No appropriate page to go to." );
- return TRUE;
- }
- gnome_druid_set_page( sxsld->sincelast_druid, gdp );
- return TRUE;
-}
-
-static void
-whattodo_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
-}
-
-static
-void
-reminders_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GtkWidget *w;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- w = glade_xml_get_widget( sxsld->gxml, REMINDER_LIST );
- gtk_clist_freeze( GTK_CLIST(w) );
- gtk_clist_clear( GTK_CLIST(w) );
- add_reminders_to_gui( sxsld->reminderList, sxsld );
- gtk_clist_thaw( GTK_CLIST(w) );
- gnome_druid_set_buttons_sensitive(
- sxsld->sincelast_druid,
- ( gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )
- != NULL ),
- TRUE, TRUE, TRUE );
- /* FIXME: this isn't quite right; see the comment in
- * sxsld_remind_row_toggle */
- gnome_druid_set_show_finish( sxsld->sincelast_druid,
- !gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- FORWARD ) );
-}
-
-static
-gboolean
-reminders_next( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GnomeDruidPage *gdp;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- if ( !processed_valid_reminders_listP( sxsld ) ) {
- return TRUE;
- }
- if ( !(gdp = gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- FORWARD )) ) {
- DEBUG( "no valid page to switch to" );
- return TRUE;
- }
- gnome_druid_set_page( sxsld->sincelast_druid, gdp );
- return TRUE;
-}
-
-static
-gboolean
-reminders_back( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GnomeDruidPage *gdp;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- if ( !processed_valid_reminders_listP( sxsld ) ) {
- return TRUE;
- }
- if ( !(gdp = gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )) ) {
- DEBUG( "no valid page to switch to" );
- return TRUE;
- }
- gnome_druid_set_page( sxsld->sincelast_druid, gdp );
- return TRUE;
-}
-
-static
-gboolean
-created_back( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld;
-
- sxsld = (sxSinceLastData*)ud;
- gnc_split_register_save(
- gnc_ledger_display_get_split_register(sxsld->created_ledger),
- TRUE );
- return gen_back( druid_page, arg1, ud );
-}
-
-static
-gboolean
-created_next( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld;
-
- sxsld = (sxSinceLastData*)ud;
- gnc_split_register_save(
- gnc_ledger_display_get_split_register(sxsld->created_ledger),
- TRUE );
- return gen_next( druid_page, arg1, ud );
-}
-
-static
-void
-created_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GList *tctList, *tciList, *guidList;
- toCreateTuple *tct;
- toCreateInstance *tci;
- Query *bookQuery, *guidQuery, *q;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- bookQuery = xaccMallocQuery();
- guidQuery = xaccMallocQuery();
- xaccQuerySetBook( bookQuery, gnc_get_current_book() );
- /* Create the appropriate query for the Created ledger; go through
- * the to-create list's instances and add all the created Txn
- * GUIDs. */
- for ( tctList = sxsld->toCreateList;
- tctList;
- tctList = tctList->next ) {
- tct = (toCreateTuple*)tctList->data;
- for ( tciList = tct->instanceList;
- tciList;
- tciList = tciList->next ) {
- tci = (toCreateInstance*)tciList->data;
- for ( guidList = tci->createdTxnGUIDs;
- guidList;
- guidList = guidList->next ) {
- xaccQueryAddGUIDMatch( guidQuery,
- (GUID*)guidList->data,
- GNC_ID_TRANS,
- QUERY_OR );
- }
- }
- }
- q = xaccQueryMerge( bookQuery, guidQuery, QUERY_AND );
- gnc_suspend_gui_refresh();
- gnc_ledger_display_set_query( sxsld->created_ledger, q );
- gnc_ledger_display_refresh( sxsld->created_ledger );
- gnc_resume_gui_refresh();
- xaccFreeQuery( q );
- xaccFreeQuery( bookQuery );
- xaccFreeQuery( guidQuery );
-
- gnome_druid_set_buttons_sensitive(
- sxsld->sincelast_druid,
- ( gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )
- != NULL ),
- TRUE, TRUE, TRUE );
-
- if ( !gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- FORWARD ) ) {
- gnome_druid_set_show_finish( sxsld->sincelast_druid, TRUE );
- }
-}
-
-static void
-obsolete_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
- add_dead_list_to_gui( sxsld->toRemoveList, sxsld );
-
- gnome_druid_set_buttons_sensitive(
- sxsld->sincelast_druid,
- ( gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )
- != NULL ),
- TRUE, TRUE, TRUE );
-}
-
-static void
-commit_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- gnome_druid_set_buttons_sensitive(
- sxsld->sincelast_druid,
- ( gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )
- != NULL ),
- TRUE, TRUE, TRUE );
-}
-
-static
-gboolean
-auto_create_back( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld;
-
- sxsld = (sxSinceLastData*)ud;
- gnc_split_register_save(
- gnc_ledger_display_get_split_register(sxsld->ac_ledger),
- TRUE );
- return gen_back( druid_page, arg1, ud );
-}
-
-static
-gboolean
-auto_create_next( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld;
-
- sxsld = (sxSinceLastData*)ud;
- gnc_split_register_save(
- gnc_ledger_display_get_split_register(sxsld->ac_ledger),
- TRUE );
- return gen_next( druid_page, arg1, ud );
-}
-
-static
-void
-auto_create_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GList *tctList, *tciList, *guidList;
- toCreateTuple *tct;
- toCreateInstance *tci;
- Query *bookQuery, *guidQuery, *q;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- bookQuery = xaccMallocQuery();
- guidQuery = xaccMallocQuery();
- xaccQuerySetBook( bookQuery, gnc_get_current_book() );
- /* Create the appropriate query for the auto-create-notify ledger; go
- * through the auto-create list's instances and add all the created
- * Txn GUIDs. */
- for ( tctList = sxsld->autoCreateList;
- tctList;
- tctList = tctList->next ) {
- gboolean unused, notifyState;
-
- tct = (toCreateTuple*)tctList->data;
- xaccSchedXactionGetAutoCreate( tct->sx, &unused, ¬ifyState );
- if ( !notifyState ) {
- continue;
- }
-
- for ( tciList = tct->instanceList;
- tciList;
- tciList = tciList->next ) {
- tci = (toCreateInstance*)tciList->data;
- for ( guidList = tci->createdTxnGUIDs;
- guidList;
- guidList = guidList->next ) {
- xaccQueryAddGUIDMatch( guidQuery,
- (GUID*)guidList->data,
- GNC_ID_TRANS,
- QUERY_OR );
- }
- }
- }
- q = xaccQueryMerge( bookQuery, guidQuery, QUERY_AND );
- gnc_suspend_gui_refresh();
- gnc_ledger_display_set_query( sxsld->ac_ledger, q );
- gnc_ledger_display_refresh( sxsld->ac_ledger );
- gnc_resume_gui_refresh();
- xaccFreeQuery( q );
- xaccFreeQuery( bookQuery );
- xaccFreeQuery( guidQuery );
-
- gnome_druid_set_buttons_sensitive(
- sxsld->sincelast_druid,
- ( gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )
- != NULL ),
- TRUE, TRUE, TRUE );
-
- if ( !gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- FORWARD ) ) {
- gnome_druid_set_show_finish( sxsld->sincelast_druid, TRUE );
- }
-}
-
-static
-void
-to_create_prep( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GtkWidget *w;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- w = glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST );
- gtk_clist_freeze( GTK_CLIST(w) );
- gtk_clist_clear( GTK_CLIST(w) );
- clean_variable_table( sxsld );
- add_to_create_list_to_gui( sxsld->toCreateList, sxsld );
- gtk_clist_thaw( GTK_CLIST(w) );
-
- gnome_druid_set_buttons_sensitive(
- sxsld->sincelast_druid,
- ( gnc_sxsld_get_appropriate_page( sxsld,
- druid_page,
- BACK )
- != NULL ),
- TRUE, TRUE, TRUE );
- /* Setup next/finish button based on the number of ready-to-go
- * to-create transactions */
- gnome_druid_set_show_finish(
- sxsld->sincelast_druid,
- ( (sxsld_get_future_created_txn_count(sxsld)
- - sxsld->autoCreatedCount) == 0 ) );
-}
-
-static
-void
-sxsld_revert_to_create_txns( sxSinceLastData *sxsld,
- toCreateInstance *tci )
-{
- GList *l = NULL;
-
- gnc_suspend_gui_refresh();
- for ( l = tci->createdTxnGUIDs;
- l; l = l->next ) {
- Transaction *t;
- t = xaccTransLookup( (GUID*)l->data,
- gnc_get_current_book() );
- g_assert( t );
- xaccTransBeginEdit( t );
- xaccTransDestroy( t );
- xaccTransCommitEdit( t );
-
- /* Remove from master list, too. */
- sxsld->createdTxnGUIDList =
- g_list_remove(
- sxsld->createdTxnGUIDList,
- l->data );
- }
- g_list_free( tci->createdTxnGUIDs );
- tci->createdTxnGUIDs = NULL;
- gnc_resume_gui_refresh();
-}
-
-/**
- * @return The count of created transactions.
- **/
-static
-gint
-sxsld_create_to_create_txns(sxSinceLastData *sxsld,
- toCreateInstance *tci,
- GList **creation_errors)
-{
- gint toRet = 0;
- GList *l = NULL;
- GList *created = NULL;
-
- /* Don't process instances we've already created transactions for
- * [list_length > 0], which haven't otherwise changed [!dirty]. */
- if ( g_list_length( tci->createdTxnGUIDs ) != 0 ) {
- /* If we've created it and the variables
- * haven't changed, skip it. */
- if ( ! tci->dirty ) {
- return toRet;
- }
- /* Otherwise, destroy the transactions and
- * re-create them below. */
-
- /* FIXME: this would be better if we could
- * re-used the existing txns we've already
- * gone through the pain of creating. */
- sxsld_revert_to_create_txns( sxsld, tci );
- }
-
- create_transactions_on(tci->parentTCT->sx,
- tci->date,
- tci,
- &created,
- creation_errors);
- tci->dirty = FALSE;
-
- /* Add to the Query for that register. */
- for ( l = created; l; l = l->next ) {
- tci->createdTxnGUIDs =
- g_list_append( tci->createdTxnGUIDs,
- (GUID*)l->data );
- toRet++;
- }
- sxsld->createdTxnGUIDList =
- g_list_concat( sxsld->createdTxnGUIDList, created );
- return toRet;
-}
-
-/**
- * Do the correct thing for the given toCreateInstance, taking into account
- * what we've done to it before [tci->prevState]. That is: if we previously
- * processed the instance as to-create/as-scheduled, and now we're postponing
- * it, we should remove the previously-created transactions and now add the
- * instance to the postponed list. See the code for full details on the
- * policy here.
- *
- * @return The count of created transactions.
- **/
-static
-gint
-sxsld_process_to_create_instance(sxSinceLastData *sxsld,
- toCreateInstance *tci,
- GList **creation_errors)
-{
- gint toRet = 0;
-
- /* Undo the previous work. */
- switch ( tci->prevState ) {
- case SX_IGNORE:
- switch ( tci->state ) {
- case SX_IGNORE:
- /* Keep ignoring. */
- break;
- case SX_POSTPONE:
- /* remove from postponed list. */
- gnc_sx_remove_defer_instance( tci->parentTCT->sx,
- tci->sxStateData );
- break;
- case SX_TO_CREATE:
- /* del prev txns. */
- sxsld_revert_to_create_txns( sxsld, tci );
- break;
- default:
- g_assert( FALSE );
- }
- break;
- case SX_POSTPONE:
- if ( tci->state != SX_POSTPONE ) {
- /* remove from postponed list. */
- gnc_sx_remove_defer_instance( tci->parentTCT->sx,
- tci->sxStateData );
- }
- break;
- case SX_TO_CREATE:
- if ( tci->state != SX_TO_CREATE ) {
- /* del prev txns. */
- sxsld_revert_to_create_txns( sxsld, tci );
- }
- break;
- case SX_UNDEF:
- /* Fine; do nothing. */
- break;
- default:
- g_assert( FALSE );
- break;
- }
-
- /* Now, process the currently-requested state. */
- switch ( tci->state ) {
- case SX_IGNORE:
- /* Fine ... just ignore it. */
- break;
- case SX_POSTPONE:
- if ( tci->prevState == SX_POSTPONE ) {
- break;
- }
- /* add to the postponed list. */
- {
- char tmpBuf[ MAX_DATE_LENGTH+1 ];
- qof_print_gdate( tmpBuf, MAX_DATE_LENGTH, tci->date );
- DEBUG( "Adding defer instance on %s for %s",
- tmpBuf,
- xaccSchedXactionGetName( tci->parentTCT->sx ) );
- }
- gnc_sx_add_defer_instance( tci->parentTCT->sx, tci->sxStateData );
- break;
- case SX_TO_CREATE:
- /* Go ahead and create... */
- toRet = sxsld_create_to_create_txns(sxsld, tci, creation_errors);
- break;
- default:
- g_assert( FALSE );
- break;
- }
-
- tci->prevState = tci->state;
-
- /* Increment the SX state regardless of what happens above. The last
- * generated SX instance is the new final state of the SX in all
- * cases [ignored, postponed or created]. */
- {
- gint tmp;
- GDate *last_occur;
- SchedXaction *sx;
-
- sx = tci->parentTCT->sx;
-
- /* Only set the last-occur-date, instance count and remaining
- * occurances if this instance is later than presently-last
- * definition in the SX; no matter what happens in the SX
- * dialog, the last instance processed sets the last-occur
- * date [and other params] to its instance date [and other
- * params]. */
- last_occur = xaccSchedXactionGetLastOccurDate( sx );
- /* If we don't have anything to do, then just return. */
- if ( g_date_valid( last_occur )
- && g_date_compare( last_occur, tci->date ) > 0 ) {
- return toRet;
- }
- xaccSchedXactionSetLastOccurDate( sx, tci->date );
-
- /* Handle an interesting corner case of postponing or
- * ignoring the first instance. We only want to incrment the
- * counters for newly-discovered-as-to-be-created SXes.
- */
- if ( tci->origState == SX_UNDEF ) {
- tmp = gnc_sx_get_instance_count( sx, NULL );
- gnc_sx_set_instance_count( sx, tmp+1 );
- if ( xaccSchedXactionHasOccurDef( sx ) ) {
- tmp = xaccSchedXactionGetRemOccur(sx);
- xaccSchedXactionSetRemOccur( sx, tmp-1 );
- }
- }
- }
-
- return toRet;
-}
-
-static
-gboolean
-sxsld_process_to_create_page( sxSinceLastData *sxsld )
-{
- GtkCTree *ct;
- GList *tcList, *tcInstList, *creation_errors;
- gboolean allVarsBound;
- toCreateTuple *tct;
- toCreateInstance *tci;
-
- ct = GTK_CTREE( glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ) );
-
- /* First: check to make sure all TCTs are 'ready' [and return if not].
- * Second: create the entries based on the variable bindings. */
- tcList = sxsld->toCreateList;
- if ( tcList == NULL ) {
- DEBUG( "No transactions to create..." );
- return FALSE;
- }
-
- for ( ; tcList ; tcList = tcList->next ) {
- tct = (toCreateTuple*)tcList->data;
- for ( tcInstList = tct->instanceList;
- tcInstList;
- tcInstList = tcInstList->next ) {
- tci = (toCreateInstance*)tcInstList->data;
-
- if ( tci->state == SX_IGNORE
- || tci->state == SX_POSTPONE ) {
- continue;
- }
-
- allVarsBound = TRUE;
- g_hash_table_foreach( tci->varBindings,
- andequal_numerics_set,
- &allVarsBound );
- if ( !allVarsBound ) {
- char tmpBuf[ MAX_DATE_LENGTH+1 ];
- qof_print_gdate( tmpBuf, MAX_DATE_LENGTH, tci->date );
- /* FIXME: this should be better-presented to the user. */
- DEBUG( "SX %s on date %s still has unbound variables.",
- xaccSchedXactionGetName(tci->parentTCT->sx), tmpBuf );
- gtk_ctree_select( ct, tci->node );
- return TRUE;
- }
- }
- }
-
- /* At this point we can assume there are to-create transactions and
- * either the instances are being postponed/ignored, or all variables
- * are bound. */
-
- tcList = sxsld->toCreateList;
- g_assert( tcList != NULL );
-
- creation_errors = NULL;
- gnc_suspend_gui_refresh();
- for ( ; tcList ; tcList = tcList->next ) {
- tct = (toCreateTuple*)tcList->data;
-
- for ( tcInstList = tct->instanceList;
- tcInstList;
- tcInstList = tcInstList->next ) {
-
- tci = (toCreateInstance*)tcInstList->data;
- sxsld_process_to_create_instance(sxsld, tci, &creation_errors);
- }
- }
- gnc_resume_gui_refresh();
- if (g_list_length(creation_errors) > 0)
- {
- creation_errors_dialog(creation_errors);
- creation_errors_free(creation_errors);
- }
- return FALSE;
-}
-
-static
-gboolean
-to_create_next( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld;
- GnomeDruidPage *nextPg;
-
- sxsld = (sxSinceLastData*)ud;
-
- /* Do the actual work processing the page. */
- if ( sxsld_process_to_create_page( sxsld ) ) {
- return TRUE;
- }
-
- /* Figure out the next page, now, given the changes we've made above.
- * This will get us a fix for Bug#95734. */
- nextPg = gnc_sxsld_get_appropriate_page( sxsld,
- GNOME_DRUID_PAGE( druid_page ),
- FORWARD );
- /* We've made the "adjust buttons on disposition-change" fix
- * which will make this assertion true. */
- g_assert( nextPg != NULL );
- gnome_druid_set_page( sxsld->sincelast_druid, nextPg );
-
- return TRUE;
-}
-
-static void
-gnc_sxsld_finish( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
- GList *sxList, *toDelPtr, *elt;
- GtkCList *cl;
- gint row;
- toDeleteTuple *tdt;
-
- gtk_widget_hide( sxsld->sincelast_window );
-
- gnc_sxsld_commit_ledgers( sxsld );
-
- /* If we're finishing from the to-create page, then process the page
- * contents. */
- if ( druid_page ==
- GNOME_DRUID_PAGE( glade_xml_get_widget( sxsld->gxml,
- TO_CREATE_PG ) ) ) {
- DEBUG( "Stopped on to-create-pg" );
- sxsld_process_to_create_page( sxsld );
- }
-
- /* Deal with the selected obsolete list elts. */
- cl = GTK_CLIST( glade_xml_get_widget( sxsld->gxml,
- SX_OBSOLETE_CLIST ) );
-
- if ( g_list_length( cl->selection ) > 0 ) {
- SchedXactionDialog *sxd;
- sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
-
- gnc_suspend_gui_refresh();
- for ( toDelPtr = cl->selection;
- toDelPtr;
- toDelPtr = toDelPtr->next ) {
-
- row = GPOINTER_TO_INT(toDelPtr->data);
- tdt = (toDeleteTuple*)gtk_clist_get_row_data( cl, row );
- elt = g_list_find( sxList, tdt->sx );
- sxList = g_list_remove_link( sxList, elt );
-
- xaccSchedXactionFree( (SchedXaction*)elt->data );
- }
- gnc_resume_gui_refresh();
-
- gnc_book_set_schedxactions( gnc_get_current_book(), sxList );
-
- sxd = (SchedXactionDialog*)
- gnc_find_first_gui_component(
- DIALOG_SCHEDXACTION_CM_CLASS, NULL, NULL );
- if ( sxd ) {
- gnc_sxd_list_refresh( sxd );
- }
- }
-
- sxsincelast_close_handler( sxsld );
-}
-
-static void
-restore_sx_temporal_state( gpointer key,
- gpointer value,
- gpointer user_data )
-{
- SchedXaction *sx;
- sxSinceLastData *sxsld;
-
- sxsld = (sxSinceLastData*)user_data;
-
- sx = (SchedXaction*)key;
- gnc_sx_revert_to_temporal_state( sx, (void*)value );
-}
-
-static gboolean
-cancel_check( GnomeDruidPage *druid_page,
- gpointer arg1, gpointer ud )
-{
- GList *l;
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
- char *lastrun_cancel_check_msg =
- _( "Canceling the Since-Last-Run dialog "
- "will revert all changes. "
- "Are you sure you want to lose all "
- "Scheduled Transaction changes?" );
-
- /* FIXME: This may now be a bug, as we might have changed the SX
- * states. */
- if ( g_list_length( sxsld->createdTxnGUIDList ) == 0 ) {
- /* There's nothing to cancel, so just do so... */
- return FALSE;
- }
-
- if ( !gnc_verify_dialog( sxsld->sincelast_window, TRUE,
- lastrun_cancel_check_msg ) ) {
- return TRUE;
- }
-
- /* Cancel policy:
- * . deleted SXes
- * . reborn
- * . created transactions
- * . deleted
- * . SXes reset
- * . auto-created transactions
- * . deleted
- * . SXes reset
- * . reminders -> created
- * . Trans deleted
- * . SXes reset
- * SXes reset [we use the temporal-state-data to take care of this]
- * . end_date || num_remain_instances
- * . last_occur_date
- */
-
- gnc_suspend_gui_refresh();
-
- /* destroy created transactions */
- if ( g_list_length( sxsld->createdTxnGUIDList ) > 0 ) {
- Transaction *t = NULL;
- for ( l = sxsld->createdTxnGUIDList; l; l = l->next ) {
- t = xaccTransLookup( (GUID*)l->data,
- gnc_get_current_book() );
- /* we used to assert, but since we allow the user a
- * register, they may have deleted 't' from their
- * view. Thus, if we can't find it, don't die; fixes
- * Bug#103182. */
- if ( t != NULL )
- {
- xaccTransBeginEdit( t );
- xaccTransDestroy( t );
- xaccTransCommitEdit( t );
- t = NULL;
- }
- }
- }
-
- /* Remove postponed SXes from their postponed lists, unless they were
- * originally postponed. */
- {
- GList *tcList, *tciList;
- toCreateTuple *tct;
- toCreateInstance *tci;
-
- for ( tcList = sxsld->toCreateList;
- tcList;
- tcList = tcList->next ) {
- tct = (toCreateTuple*)tcList->data;
- for ( tciList = tct->instanceList;
- tciList;
- tciList = tciList->next ) {
- tci = (toCreateInstance*)tciList->data;
- if ( tci->prevState == SX_POSTPONE
- && tci->origState != SX_POSTPONE ) {
- /* Any valid [non-null] 'prevState !=
- * SX_POSTPONE' sx temporal state
- * pointers will be destroyed at the
- * destruction of the dialog [the
- * non-cancel case], so if we need to
- * deal with those here, we should do
- * so.
- */
- gnc_sx_remove_defer_instance( tct->sx, tci->sxStateData );
- gnc_sx_destroy_temporal_state( tci->sxStateData );
- tci->sxStateData = NULL;
- }
- }
- }
- }
-
- /* Restore the temporal state of all SXes.
- * This is in sxInitStates [a bunch of opaque void *'s ... which
- * should be freed when we're done to prevent a memory leak.] */
- g_hash_table_foreach( sxsld->sxInitStates,
- restore_sx_temporal_state,
- (gpointer)sxsld );
- /* This will get destroyed when the dialog is, which will happen
- * shortly after this return. */
-
- gnc_resume_gui_refresh();
- return FALSE;
-}
-
-
-static void
-sxsincelast_init( sxSinceLastData *sxsld )
-{
- GtkWidget *w;
- GObject *o;
- GnomeDruidPage *nextPage;
- GList *creation_errors;
- int i;
- static widgetSignalHandlerTuple widgets[] = {
- { SINCELAST_DRUID, "cancel", sxsincelast_druid_cancelled },
-
- { REMINDER_LIST, "tree-select-row", sxsld_remind_row_toggle },
- { REMINDER_LIST, "tree-unselect-row", sxsld_remind_row_toggle },
-
- { TO_CREATE_LIST, "tree-select-row", sxsincelast_tc_row_sel },
- { TO_CREATE_LIST, "tree-unselect-row", sxsincelast_tc_row_unsel },
-
- { SX_OBSOLETE_CLIST, "select-row", sxsld_obsolete_row_toggle },
- { SX_OBSOLETE_CLIST, "unselect-row", sxsld_obsolete_row_toggle },
-
- { SELECT_ALL_BUTTON, "clicked",
- sx_obsolete_select_all_clicked },
- { UNSELECT_ALL_BUTTON, "clicked",
- sx_obsolete_unselect_all_clicked },
-
- { NULL, NULL, NULL }
- };
-
- static druidSignalHandlerTuple pages[] = {
- { WHAT_TO_DO_PG,
- whattodo_prep, NULL, NULL,
- NULL, cancel_check },
-
- { REMINDERS_PG,
- reminders_prep, reminders_back, reminders_next,
- gnc_sxsld_finish, cancel_check },
-
- { AUTO_CREATE_NOTIFY_PG,
- auto_create_prep, auto_create_back, auto_create_next,
- gnc_sxsld_finish, cancel_check },
-
- { TO_CREATE_PG,
- to_create_prep, gen_back, to_create_next,
- gnc_sxsld_finish, cancel_check },
-
- { CREATED_PG,
- created_prep, created_back, created_next,
- gnc_sxsld_finish, cancel_check },
-
- { OBSOLETE_PG,
- obsolete_prep, gen_back, gen_next,
- gnc_sxsld_finish, cancel_check },
-
- { COMMIT_PG,
- commit_prep, gen_back, gen_next,
- gnc_sxsld_finish, cancel_check },
-
- { NULL, NULL, NULL, NULL, NULL, NULL }
- };
-
- static const struct optionMenuTuple {
- char *name;
- void (*fn)();
- } optionMenus[] = {
- { SX_DISPOSITION_OPT, sxsld_disposition_changed },
- { NULL, NULL }
- };
-
-
- gnc_register_gui_component( DIALOG_SXSINCELAST_CM_CLASS,
- NULL,
- sxsincelast_close_handler,
- sxsld->sincelast_window );
-
- g_signal_connect( G_OBJECT(sxsld->sincelast_window), "destroy",
- G_CALLBACK( sxsincelast_destroy ), sxsld );
-
- dialog_widgets_attach_handlers(sxsld->gxml, widgets, sxsld);
- druid_pages_attach_handlers( sxsld->gxml, pages, sxsld );
-
- /* gnc-init the option menu[s]. */
- for ( i=0; optionMenus[i].name != NULL; i++ ) {
- w = glade_xml_get_widget( sxsld->gxml, optionMenus[i].name );
- gnc_option_menu_init( w );
- o = G_OBJECT(gtk_option_menu_get_menu(GTK_OPTION_MENU(w)));
- g_signal_connect( o, "selection-done",
- G_CALLBACK( optionMenus[i].fn ),
- sxsld );
- }
-
- /* set all to-create clist columns to auto-resize. */
- w = glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST );
- clist_set_all_cols_autoresize(GTK_CLIST(w), TO_CREATE_LIST_WIDTH);
- w = glade_xml_get_widget( sxsld->gxml, REMINDER_LIST );
- clist_set_all_cols_autoresize(GTK_CLIST(w), REMINDER_LIST_WIDTH);
- w = glade_xml_get_widget( sxsld->gxml, SX_OBSOLETE_CLIST );
- clist_set_all_cols_autoresize(GTK_CLIST(w), SX_OBSOLETE_CLIST_WIDTH);
-
- sxsld->prog = GTK_PROGRESS_BAR(glade_xml_get_widget( sxsld->gxml,
- WHAT_TO_DO_PROGRESS ));
-
- sxsld->toCreateStatus =
- GTK_STATUSBAR(
- glade_xml_get_widget( sxsld->gxml, TO_CREATE_STATUS ) );
- sxsld->statusCtxId =
- gtk_statusbar_get_context_id( sxsld->toCreateStatus,
- /* Sure, we're overusing this
- * string, but I don't see why
- * the Statusbar even
- * cares... */
- TO_CREATE_STATUS );
-
- /* The last druid page is blank without this call. */
- gtk_widget_show_all( sxsld->sincelast_window );
-
- create_autoCreate_ledger( sxsld );
- create_created_ledger( sxsld );
- create_to_create_ledger( sxsld );
-
- gnc_restore_window_size(GCONF_SECTION, GTK_WINDOW(sxsld->sincelast_window));
-
- /* Do not call show_all here. Screws up the gtkuimanager code */
- gtk_widget_show( sxsld->sincelast_window );
-
- creation_errors = NULL;
- process_auto_create_list(sxsld->autoCreateList, sxsld, &creation_errors);
- if (g_list_length(creation_errors) > 0)
- {
- creation_errors_dialog(creation_errors);
- creation_errors_free(creation_errors);
- }
-
- w = glade_xml_get_widget( sxsld->gxml, WHAT_TO_DO_PG );
- nextPage = gnc_sxsld_get_appropriate_page( sxsld,
- GNOME_DRUID_PAGE(w),
- FORWARD );
-
- /* If there's nowhere to go, then we shouldn't have been started at
- * all [ie., ..._populate should have returned FALSE]. */
- g_assert( nextPage );
-
- gnome_druid_set_page( sxsld->sincelast_druid, nextPage );
-}
-
-static
-void
-sxsincelast_save_size( sxSinceLastData *sxsld )
-{
- gnc_save_window_size( GCONF_SECTION, GTK_WINDOW(sxsld->sincelast_window) );
-}
-
-static void
-generate_instances(SchedXaction *sx,
- GDate *end,
- GDate *reminderEnd,
- GList **instanceList,
- GList **reminderList,
- GList **deadList)
-{
- GDate gd;
- toCreateInstance *tci;
- reminderTuple *rt;
- reminderInstanceTuple *rit;
- void *seqStateData;
-
- g_assert( g_date_valid(end) );
- g_assert( g_date_valid(reminderEnd) );
-
- g_date_clear(&gd, 1);
-
- /* Process valid next instances. */
- seqStateData = gnc_sx_create_temporal_state( sx );
- //gd = xaccSchedXactionGetNextInstance( sx, seqStateData );
- gd = xaccSchedXactionGetInstanceAfter( sx, &gd, seqStateData );
- while ( g_date_valid(&gd)
- && g_date_compare( &gd, end ) <= 0 ) {
-
- tci = g_new0( toCreateInstance, 1 );
-
- tci->dirty = FALSE;
- tci->date = g_date_new();
- *tci->date = gd;
- tci->origState = SX_UNDEF;
- tci->state = SX_TO_CREATE;
- tci->prevState = SX_UNDEF;
- tci->sxStateData =
- gnc_sx_clone_temporal_state( seqStateData );
- *instanceList = g_list_append( *instanceList, tci );
-
- gnc_sx_incr_temporal_state( sx, seqStateData );
- gd = xaccSchedXactionGetInstanceAfter( sx, &gd, seqStateData );
- }
-
- /* Process reminder instances or add to dead list [if we have one] */
- if ( g_date_valid( &gd ) ) {
- rt = g_new0( reminderTuple, 1 );
- rt->sx = sx;
- rt->instanceList = NULL;
- while ( g_date_valid(&gd)
- && g_date_compare( &gd, reminderEnd ) <= 0 ) {
-
- rit = g_new0( reminderInstanceTuple, 1 );
- rit->endDate = g_date_new();
- *rit->endDate = *end;
- rit->occurDate = g_date_new();
- *rit->occurDate = gd;
- rit->isSelected = FALSE;
- rit->parentRT = rt;
- rit->sxStateData =
- gnc_sx_clone_temporal_state( seqStateData );
- rt->instanceList = g_list_append( rt->instanceList, rit );
-
- gnc_sx_incr_temporal_state( sx, seqStateData );
- gd = xaccSchedXactionGetInstanceAfter( sx, &gd, seqStateData );
- }
- if ( rt->instanceList != NULL ) {
- *reminderList = g_list_append( *reminderList, rt );
- } else {
- g_free( rt );
- }
- rt = NULL;
- } else if ( deadList ) {
- toDeleteTuple *tdt;
-
- tdt = g_new0( toDeleteTuple, 1 );
- tdt->sx = sx;
- tdt->endDate = g_date_new();
- *tdt->endDate = gd;
- *deadList = g_list_append( *deadList, tdt );
- } /* else { this else intentionally left blank: drop the SX on the
- * floor at this point. } */
-
- gnc_sx_destroy_temporal_state( seqStateData );
- seqStateData = NULL;
-}
-
-static void
-_free_varBindings_hash_elts( gpointer key, gpointer value, gpointer data )
-{
- g_assert( key );
- g_free( key );
- if ( value )
- g_free( value );
-}
-
-static void
-process_auto_create_list(GList *autoCreateList, sxSinceLastData *sxsld, GList **creation_errors)
-{
- toCreateTuple *tct;
- toCreateInstance *tci;
- GList *instances;
-
- gnc_suspend_gui_refresh();
-
- for ( ; autoCreateList ; autoCreateList = autoCreateList->next ) {
- tct = (toCreateTuple*)autoCreateList->data;
-
- for ( instances = tct->instanceList;
- instances;
- instances = instances->next ) {
- tci = (toCreateInstance*)instances->data;
- sxsld->autoCreatedCount +=
- sxsld_process_to_create_instance( sxsld, tci, creation_errors );
- }
- }
- gnc_resume_gui_refresh();
-}
-
-static
-void
-add_to_create_list_to_gui( GList *toCreateList, sxSinceLastData *sxsld )
-{
- toCreateTuple *tct;
- toCreateInstance *tci;
- GtkCTree *ct;
- GtkCTreeNode *sxNode;
- GtkCTreeNode *firstToBeProcessedRow;
- char *rowText[ TO_CREATE_LIST_WIDTH ];
- GList *insts;
-
- ct = GTK_CTREE( glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ) );
-
- firstToBeProcessedRow = NULL;
- for ( ; toCreateList ; toCreateList = toCreateList->next ) {
- tct = (toCreateTuple*)toCreateList->data;
-
- rowText[0] = xaccSchedXactionGetName( tct->sx );
- rowText[1] = "";
-
- sxNode = gtk_ctree_insert_node( ct, NULL, NULL,
- rowText,
- 0, NULL, NULL, NULL, NULL,
- FALSE, TRUE );
-
- for ( insts = tct->instanceList;
- insts;
- insts = insts->next ) {
- gboolean allVarsBound = FALSE;
-
- tci = (toCreateInstance*)insts->data;
-
- /* tct->{sx,date} are already filled in. */
- if ( ! tci->varBindings ) {
- tci->varBindings = g_hash_table_new( g_str_hash,
- g_str_equal );
-
- sxsl_get_sx_vars( tci->parentTCT->sx,
- tci->varBindings );
- }
-
- rowText[0] = g_new0( char, MAX_DATE_LENGTH+1 );
- qof_print_gdate( rowText[0], MAX_DATE_LENGTH, tci->date );
-
-
- switch ( tci->state ) {
- case SX_TO_CREATE:
- allVarsBound = TRUE;
- g_hash_table_foreach( tci->varBindings,
- andequal_numerics_set,
- &allVarsBound );
- rowText[1] = ( allVarsBound
- ? _( "Ready to create" ) /* READY_TEXT */
- : _( "Needs values for variables" ) /* NEEDS_BINDINGS_TEXT */
- );
- break;
- case SX_IGNORE:
- rowText[1] = _( "Ignored" ) /* IGNORE_TEXT */ ;
- break;
- case SX_POSTPONE:
- rowText[1] = _( "Postponed" ) /* POSTPONE_TEXT */ ;
- break;
- default:
- g_assert( FALSE );
- }
-
- tci->node = gtk_ctree_insert_node( ct, sxNode, NULL,
- rowText,
- 0, NULL, NULL, NULL, NULL,
- TRUE, FALSE );
- if ( !allVarsBound && !firstToBeProcessedRow ) {
- firstToBeProcessedRow = tci->node;
- }
- gtk_ctree_node_set_row_data( ct, tci->node, tci );
- g_free( rowText[0] );
- }
- }
-
- /* Setup the first thing to be processed, or disable controls. */
- if ( firstToBeProcessedRow ) {
- gtk_ctree_select( ct, firstToBeProcessedRow );
- sxsld_set_sensitive_tci_controls( sxsld, TRUE );
- } else {
- sxsld_set_sensitive_tci_controls( sxsld, FALSE );
- }
-}
-
-static
-void
-add_reminders_to_gui( GList *reminderList, sxSinceLastData *sxsld )
-{
- GtkCTree *ctree;
- GtkCTreeNode *sxNode, *instNode;
- char *rowText[REMINDER_LIST_WIDTH];
- reminderTuple *rt;
- GList *instances;
- reminderInstanceTuple *rit;
- FreqSpec *fs;
- GString *freqSpecStr;
-
- ctree = GTK_CTREE( glade_xml_get_widget( sxsld->gxml,
- REMINDER_LIST ) );
-
- for ( ; reminderList; reminderList = reminderList->next ) {
- rt = (reminderTuple*)reminderList->data;
-
- rowText[0] = xaccSchedXactionGetName( rt->sx );
- fs = xaccSchedXactionGetFreqSpec( rt->sx );
- freqSpecStr = g_string_sized_new( 16 );
- xaccFreqSpecGetFreqStr( fs, freqSpecStr );
- rowText[1] = freqSpecStr->str;
- rowText[2] = ""; /* Days Away */
- sxNode = gtk_ctree_insert_node( ctree, NULL, NULL, rowText,
- 0, /* spacing */
- NULL, NULL, NULL, NULL, /* pixmaps */
- FALSE, /* leafP */
- TRUE ); /* expandedP */
- g_string_free( freqSpecStr, TRUE );
-
- /* The SX node itself isn't selectable; only the
- * instances. */
- gtk_ctree_node_set_selectable( ctree, sxNode, FALSE );
- for ( instances = rt->instanceList;
- instances;
- instances = instances->next ) {
- rit = (reminderInstanceTuple*)instances->data;
-
- rowText[0] = g_new0( gchar, MAX_DATE_LENGTH+1 );
- qof_print_gdate( rowText[0], MAX_DATE_LENGTH, rit->occurDate );
- rowText[1] = "";
- rowText[2] = g_new0( gchar, 5 ); /* FIXME: appropriate size? */
- sprintf( rowText[2], "%d",
- (g_date_get_julian(rit->occurDate)
- - g_date_get_julian(rit->endDate)) );
-
- instNode = gtk_ctree_insert_node( ctree, sxNode, NULL,
- rowText,
- 0, NULL, NULL, NULL, NULL,
- TRUE, TRUE );
- gtk_ctree_node_set_row_data( ctree,
- instNode,
- (gpointer)rit );
- g_signal_handlers_block_by_func( G_OBJECT(ctree),
- sxsld_remind_row_toggle,
- sxsld );
- if ( rit->isSelected ) {
- gtk_ctree_select( ctree, instNode );
- }
- g_signal_handlers_unblock_by_func( G_OBJECT(ctree),
- sxsld_remind_row_toggle,
- sxsld );
- g_free( rowText[0] );
- g_free( rowText[2] );
- }
- }
-}
-
-static void
-add_dead_list_to_gui(GList *removeList, sxSinceLastData *sxsld)
-{
- GtkCList *cl;
- char *rowtext[3];
- int row;
- GString *tmp_str;
- toDeleteTuple *tdt;
- FreqSpec *fs;
- cl = GTK_CLIST( glade_xml_get_widget( sxsld->gxml,
- SX_OBSOLETE_CLIST ));
-
- tmp_str = g_string_new(NULL);
- rowtext[2] = g_strdup( _("Obsolete") );
-
- gtk_clist_freeze( cl );
- gtk_clist_clear( cl );
- g_signal_handlers_block_by_func( G_OBJECT(cl),
- sxsld_obsolete_row_toggle,
- sxsld );
-
- for ( row = 0; removeList;
- row++, removeList = removeList->next ) {
- tdt = (toDeleteTuple*)removeList->data;
-
- rowtext[0] = xaccSchedXactionGetName( tdt->sx );
-
- fs = xaccSchedXactionGetFreqSpec( tdt->sx );
- xaccFreqSpecGetFreqStr( fs, tmp_str );
- /* XXX are we leaking memory here, by not
- * freeing previous rrowtext[1] ?? */
- rowtext[1] = tmp_str->str;
-
- gtk_clist_insert( cl, row, rowtext );
- gtk_clist_set_row_data( cl, row, tdt );
- if ( tdt->isSelected ) {
- gtk_clist_select_row( cl, row, 0 );
- }
- }
- g_signal_handlers_unblock_by_func( G_OBJECT(cl),
- sxsld_obsolete_row_toggle,
- sxsld );
- gtk_clist_thaw( cl );
-
- g_string_free(tmp_str, TRUE);
- g_free(rowtext[2]);
-}
-
-/**
- * Moves the selected reminders to the appropriate [auto-create or to-create]
- * sections of the since-last-run dialog.
- **/
-static void
-processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
-{
- GList *list = NULL;
- GList **containingList;
- reminderInstanceTuple *rit;
- toCreateTuple *tct;
- toCreateInstance *tci;
- gboolean autoCreateOpt, notifyOpt;
-
- tct = NULL;
- for ( ; goodList ; goodList = goodList->next ) {
- rit = (reminderInstanceTuple*)goodList->data;
-
- /* skip over reminders we've already created [in the
- * past]. */
- if ( rit->resultantTCI )
- continue;
-
- xaccSchedXactionGetAutoCreate( rit->parentRT->sx,
- &autoCreateOpt, ¬ifyOpt );
- containingList = ( autoCreateOpt
- ? &sxsld->autoCreateList
- : &sxsld->toCreateList );
- for ( list = *containingList;
- list;
- list = list->next ) {
- tct = (toCreateTuple*)list->data;
- /* Find any already-existing toCreateTuples to add to...*/
- if ( tct->sx == rit->parentRT->sx ) {
- break;
- }
- }
- if ( !list ) {
- tct = g_new0( toCreateTuple, 1 );
- tct->sx = rit->parentRT->sx;
- *containingList =
- g_list_append( *containingList, tct );
- }
-
- tci = g_new0( toCreateInstance, 1 );
- tci->dirty = FALSE;
- tci->parentTCT = tct;
- tci->date = g_date_new();
- *tci->date = *rit->occurDate;
- tci->state = SX_TO_CREATE;
- tci->prevState = SX_UNDEF;
- tci->origState = SX_UNDEF;
- tci->varBindings = NULL;
- tci->node = NULL;
- tci->sxStateData = rit->sxStateData;
-
- tct->instanceList =
- g_list_append( tct->instanceList, tci );
-
- /* special auto-create-opt processing; process it now. */
- if ( autoCreateOpt ) {
- GList *creation_errors = NULL;
- list = NULL;
- list = g_list_append( list, tct );
- process_auto_create_list( list, sxsld, &creation_errors );
- list = NULL;
- }
-
- /* save the resultant just-created TCI in the RIT in case
- * things change later. */
- rit->resultantTCI = tci;
- }
-}
-
-/**
- * @see gnc_ui_sxsincelast_dialog_create for the return value definition.
- **/
-static
-gint
-sxsincelast_populate( sxSinceLastData *sxsld )
-{
- int toRet = 0;
- gboolean onlyNoNotify = TRUE;
- GList *sxList, *instanceList, *l, **containingList;
- SchedXaction *sx;
- GDate end, endPlusReminders;
- gint daysInAdvance;
- gboolean autocreateState, notifyState;
- toCreateTuple *tct;
- toCreateInstance *tci;
-
- instanceList = NULL;
- sxList = gnc_book_get_schedxactions( gnc_get_current_book () );
-
- if ( sxList == NULL ) {
- DEBUG( "No scheduled transactions to populate." );
- return toRet;
- }
-
- for ( ; sxList; sxList = sxList->next ) {
- sx = (SchedXaction*)sxList->data;
-
- /* Store initial state of SX. */
- if ( g_hash_table_lookup( sxsld->sxInitStates, sx )
- != NULL ) {
- PERR( "Why are we able to find a SX initial state "
- "hash entry for something we're seeing for "
- "the first time?" );
- return toRet;
- }
- {
- void *sx_state;
- sx_state = gnc_sx_create_temporal_state( sx );
- g_hash_table_insert( sxsld->sxInitStates,
- sx, sx_state );
- sx_state = NULL;
- }
-
- g_date_set_time_t( &end, time(NULL) );
- daysInAdvance = xaccSchedXactionGetAdvanceCreation( sx );
- g_date_add_days( &end, daysInAdvance );
-
- endPlusReminders = end;
- daysInAdvance = xaccSchedXactionGetAdvanceReminder(sx);
- g_date_add_days(&endPlusReminders, daysInAdvance);
-
- /* Handle postponed instances.
- *
- * Postponed instances, by definition, are always at the
- * front of the instance list. As well, they're always valid
- * instances [not reminders]. */
-
- /* FIXME: postponed instances _may_ create an obsolete
- * instance. */
- {
- GList *postponed, *l;
-
- postponed = gnc_sx_get_defer_instances( sx );
-
- for ( l = postponed; l; l = l->next ) {
- onlyNoNotify = FALSE;
-
- tci = g_new0( toCreateInstance, 1 );
- tci->sxStateData = (void*)l->data;
- tci->date = g_date_new();
- *tci->date =
- xaccSchedXactionGetNextInstance(
- sx, tci->sxStateData );
- tci->dirty = FALSE;
- tci->state = SX_POSTPONE;
- tci->prevState = SX_POSTPONE;
- tci->origState = SX_POSTPONE;
-
- instanceList = g_list_append( instanceList, tci );
- tci = NULL;
- }
-
- }
-
- generate_instances(sx,
- &end,
- &endPlusReminders,
- &instanceList,
- &sxsld->reminderList,
- &sxsld->toRemoveList);
-
- if (instanceList == NULL)
- continue;
-
- xaccSchedXactionGetAutoCreate(sx, &autocreateState, ¬ifyState);
- /* Figure out the appropriate list to place the new TCT on. */
- containingList = ( autocreateState
- ? &sxsld->autoCreateList
- : &sxsld->toCreateList );
-
- tct = g_new0( toCreateTuple, 1 );
- tct->sx = sx;
- for ( l = instanceList ; l; l = l->next ) {
-
- /* only count the no-notify txns for this. */
- if ( autocreateState && !notifyState ) {
- onlyNoNotify &= (!notifyState);
- toRet++;
- }
-
- tci = (toCreateInstance*)l->data;
- tci->parentTCT = tct;
-
- tct->instanceList =
- g_list_append( tct->instanceList, tci );
- }
-
- g_list_free( instanceList );
- instanceList = NULL;
-
- /* abstractly place the TCT onto the afore-determined list. */
- *containingList = g_list_append( *containingList, tct );
- }
-
- /* Return appropriately. */
- {
- gboolean stuffToDo =
- ( g_list_length( sxsld->toRemoveList ) > 0
- || g_list_length( sxsld->reminderList ) > 0
- || g_list_length( sxsld->toCreateList ) > 0 );
- if ( onlyNoNotify && !stuffToDo ) {
- toRet = -(toRet);
- }
-
- if ( toRet == 0
- && ( stuffToDo
- || g_list_length( sxsld->autoCreateList ) > 0 ) ) {
- toRet = INT_MAX;
- }
- }
-
- /* if we're about to return a negative value [indicating only
- * auto-create no-notify txns], then actually create them. */
- if ( toRet < 0 ) {
- GList *creation_errors = NULL;
- process_auto_create_list( sxsld->autoCreateList, sxsld, &creation_errors );
- if (g_list_length(creation_errors) > 0)
- {
- creation_errors_dialog(creation_errors);
- creation_errors_free(creation_errors);
- }
- }
-
- return toRet;
-}
-
-static void
-sxsincelast_close_handler( gpointer ud )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- gtk_widget_hide( sxsld->sincelast_window );
- sxsincelast_save_size( sxsld );
- gtk_widget_destroy( sxsld->sincelast_window );
- /* The data will be cleaned up in the destroy handler. */
-}
-
-static void
-andequal_numerics_set( gpointer key, gpointer value, gpointer data )
-{
- gboolean *allVarsBound = data;
- if ( strcmp( (gchar*)key, "i" ) == 0 ) {
- return;
- }
- *allVarsBound &= (value != NULL);
-}
-
-static void
-sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
-{
- sxSinceLastData *sxsld;
- gchar *varName;
- toCreateInstance *tci;
- gchar *entryText;
- gnc_numeric *num, *ourNum;
- GHashTable *dummyVarHash;
- static const int MSG_BUF_LEN = 127;
- char msgBuf[MSG_BUF_LEN+1];
-
- sxsld = (sxSinceLastData*)ud;
-
- tci = (toCreateInstance*)g_object_get_data( G_OBJECT(e), "tci" );
- g_assert( tci == sxsld->curSelTCI );
-
- varName = (gchar*)g_object_get_data( G_OBJECT(e), "varName" );
- num = (gnc_numeric*)g_object_get_data( G_OBJECT(e), "numeric" );
- entryText = gtk_editable_get_chars( e, 0, -1 );
- dummyVarHash = g_hash_table_new( NULL, NULL );
- /* FIXME?: Should be using xaccParseAmount instead of
- * parser_parse_separate_vars? */
- gtk_statusbar_pop( sxsld->toCreateStatus, sxsld->statusCtxId );
-
- if ( !gnc_exp_parser_parse_separate_vars( entryText, num,
- NULL, dummyVarHash ) ) {
- num = NULL;
- if ( entryText != NULL
- && strlen(entryText) > 0 ) {
- snprintf( msgBuf, MSG_BUF_LEN,
- "error parsing entry near \"%s\"", entryText );
- gtk_statusbar_push( sxsld->toCreateStatus,
- sxsld->statusCtxId,
- msgBuf );
- }
- } else if ( g_hash_table_size( dummyVarHash ) != 0 ) {
- num = NULL;
- snprintf( msgBuf, MSG_BUF_LEN,
- "No new variables allowed in "
- "expression \"%s\"", entryText );
- gtk_statusbar_push( sxsld->toCreateStatus,
- sxsld->statusCtxId,
- msgBuf );
- } else if ( gnc_numeric_check( *num ) != GNC_ERROR_OK ) {
- snprintf( msgBuf, MSG_BUF_LEN,
- "Entry \"%s\" is not "
- "parseable", entryText );
- gtk_statusbar_push( sxsld->toCreateStatus,
- sxsld->statusCtxId,
- msgBuf );
- num = NULL;
- } else {
- snprintf( msgBuf, MSG_BUF_LEN,
- "%f", gnc_numeric_to_double( *num ) );
- gtk_statusbar_push( sxsld->toCreateStatus,
- sxsld->statusCtxId,
- msgBuf );
- }
-
- g_hash_table_foreach( dummyVarHash,
- _free_varBindings_hash_elts,
- NULL );
- g_hash_table_destroy( dummyVarHash );
-
- {
- gpointer maybeKey, maybeValue;
-
- ourNum = NULL;
- if ( num ) {
- ourNum = g_new0( gnc_numeric, 1 );
- *ourNum = *num;
- }
- if ( g_hash_table_lookup_extended( tci->varBindings, varName,
- &maybeKey, &maybeValue ) ) {
- g_hash_table_remove( tci->varBindings, maybeKey );
- /* only if not null. */
- if ( maybeValue ) {
- g_free( maybeValue );
- }
- }
- g_hash_table_insert( tci->varBindings, varName, ourNum );
- tci->dirty = TRUE;
- }
-
-
- {
- GtkCTree *ct;
- gboolean allVarsBound = TRUE;
-
- /* If there are no un-bound variables, then set the 'ready-to-go'
- flag to 'y'. */
- g_hash_table_foreach( tci->varBindings,
- andequal_numerics_set,
- &allVarsBound );
- ct = GTK_CTREE(glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ));
- gtk_ctree_node_set_text( ct, tci->node, 1,
- ( allVarsBound
- ? _( READY_TEXT )
- : _( NEEDS_BINDINGS_TEXT ) ) );
- }
-}
-
-static void
-sxsincelast_destroy( GtkObject *o, gpointer ud )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)ud;
-
- /* appropriate place to destroy data structures */
- clean_sincelast_data( sxsld );
-
- gnc_embedded_window_close_page(sxsld->ac_window, sxsld->ac_register);
- gtk_widget_destroy(GTK_WIDGET(sxsld->ac_window));
- sxsld->ac_window = NULL;
- sxsld->ac_register = NULL;
- sxsld->ac_ledger = NULL;
-
- gnc_embedded_window_close_page(sxsld->created_window,
- sxsld->created_register);
- gtk_widget_destroy(GTK_WIDGET(sxsld->created_window));
- sxsld->created_window = NULL;
- sxsld->created_register = NULL;
- sxsld->created_ledger = NULL;
-
- gnc_embedded_window_close_page(sxsld->to_create_window,
- sxsld->to_create_register);
- gtk_widget_destroy(GTK_WIDGET(sxsld->to_create_window));
- sxsld->to_create_window = NULL;
- sxsld->to_create_register = NULL;
- sxsld->to_create_ledger = NULL;
-
- gnc_unregister_gui_component_by_data( DIALOG_SXSINCELAST_CM_CLASS,
- sxsld->sincelast_window );
-
- g_free( sxsld );
-}
-
-/**
- * Used to copy the varBinding GHashTable.
- **/
-static
-void
-gnc_sxsl_copy_ea_hash( gpointer key,
- gpointer value,
- gpointer user_data )
-{
- gchar *name = (gchar*)key;
- gnc_numeric *val = (gnc_numeric*)value;
- gnc_numeric *newVal;
- GHashTable *table = (GHashTable*)user_data;
-
- newVal = g_new0( gnc_numeric, 1 );
- *newVal = gnc_numeric_error( -2 );
- if ( val )
- *newVal = *val;
-
- g_assert( name );
-
- g_hash_table_insert( table,
- (gpointer)g_strdup( name ),
- (gpointer)newVal );
-}
-
-static
-void
-gnc_sxsl_del_vars_table_ea( gpointer key,
- gpointer value,
- gpointer user_data )
-{
- g_assert( key );
- if ( key )
- g_free( (gchar*)key );
- if ( value )
- g_free( (gnc_numeric*)value );
-}
-
-static gint
-create_each_transaction_helper( Transaction *t, void *d )
-{
- Transaction *newT;
- GList *sList;
- GList *osList;
- Split *split;
- kvp_frame *split_kvpf;
- kvp_value *kvp_val;
- gboolean errFlag;
- createData *createUD;
- toCreateInstance *tci;
- gnc_commodity *first_cmdty = NULL;
- GHashTable *actualVars;
- gnc_numeric *varIValue;
-
- errFlag = FALSE;
-
- /* FIXME: In general, this should [correctly] deal with errors such
- as not finding the approrpiate Accounts and not being able to
- parse the formula|credit/debit strings. */
-
- /* FIXME: when we copy the trans_onto_trans, we don't want to copy
- the Split's kvp_frames... */
-
- createUD = (createData*)d;
- tci = createUD->tci;
-
- newT = xaccMallocTransaction(gnc_get_current_book ());
- xaccTransBeginEdit( newT );
- /* the action and description/memo are in the template */
- gnc_copy_trans_onto_trans( t, newT, FALSE, FALSE );
-
- xaccTransSetDate( newT,
- g_date_get_day( tci->date ),
- g_date_get_month( tci->date ),
- g_date_get_year( tci->date ) );
-
- /* the accounts and amounts are in the kvp_frames of the splits. */
- osList = xaccTransGetSplitList( t );
- sList = xaccTransGetSplitList( newT );
- if ( (osList == NULL) || (sList == NULL) ) {
- PERR( "\tseen transaction w/o splits. :(" );
- xaccTransDestroy( newT );
- xaccTransCommitEdit( newT );
- return 13;
- }
-
- /* Setup the predefined variables for credit/debit formula
- * processing. */
- actualVars = g_hash_table_new( g_str_hash, g_str_equal );
- if ( tci->varBindings != NULL ) {
- g_hash_table_foreach( tci->varBindings,
- gnc_sxsl_copy_ea_hash, actualVars );
- }
- varIValue = g_new0( gnc_numeric, 1 );
- *varIValue =
- gnc_numeric_create(
- gnc_sx_get_instance_count( tci->parentTCT->sx,
- tci->sxStateData ),
- 1 );
- /* It's really important that we strdup "i" here, so we can
- * generically cleanup with a simple 'foreach' that blindly frees the
- * keys, below. */
- g_hash_table_insert( actualVars, g_strdup("i"), varIValue );
-
- for ( ; sList && osList; sList = sList->next, osList = osList->next)
- {
- Account *acct;
- gnc_commodity *split_cmdty = NULL;
-
- split = (Split*)sList->data;
-
- /* FIXME: Ick. This assumes that the split lists will be
- ordered identically. :( I think it's fair to say they
- will, but I'd rather not have to count on it. --jsled */
- split_kvpf = xaccSplitGetSlots( (Split*)osList->data );
-
- /* from-transaction of splits */
- /* This needs to be before the value setting [below] so the
- * balance calculations can work. */
- {
- GUID *acct_guid;
- /* contains the guid of the split's actual account. */
- kvp_val = kvp_frame_get_slot_path( split_kvpf,
- GNC_SX_ID,
- GNC_SX_ACCOUNT,
- NULL );
- if (kvp_val == NULL) {
- GString *err = g_string_new("");
- g_string_printf(err, "Null account kvp value for SX [%s], cancelling creation.",
- xaccSchedXactionGetName(createUD->tci->parentTCT->sx));
- *createUD->creation_errors = g_list_append(*createUD->creation_errors, err);
- errFlag = TRUE;
- break;
- }
- acct_guid = kvp_value_get_guid( kvp_val );
- acct = xaccAccountLookup( acct_guid, gnc_get_current_book ());
- if (acct == NULL)
- {
- const char *guidStr;
- GString *err;
- guidStr = guid_to_string((const GUID*)acct_guid);
- err = g_string_new("");
- g_string_printf(err, "Unknown account for guid [%s], cancelling SX [%s] creation.",
- guidStr, xaccSchedXactionGetName(createUD->tci->parentTCT->sx));
- g_free((char*)guidStr);
- *createUD->creation_errors = g_list_append(*createUD->creation_errors, err);
- errFlag = TRUE;
- break;
- }
-
- split_cmdty = xaccAccountGetCommodity(acct);
- if (first_cmdty == NULL)
- {
- first_cmdty = split_cmdty;
- xaccTransSetCurrency(newT, first_cmdty);
- }
-
- xaccAccountBeginEdit(acct);
- xaccAccountInsertSplit(acct, split);
- }
-
- /* credit/debit formulas */
- {
- char *str, *parseErrorLoc;
- gnc_numeric credit_num, debit_num, final;
- int gncn_error;
-
- kvp_val = kvp_frame_get_slot_path( split_kvpf,
- GNC_SX_ID,
- GNC_SX_CREDIT_FORMULA,
- NULL);
- str = kvp_value_get_string( kvp_val );
- credit_num = gnc_numeric_create( 0, 1 );
- if (str != NULL && strlen(str) != 0) {
- if (!gnc_exp_parser_parse_separate_vars(str, &credit_num,
- &parseErrorLoc,
- actualVars))
- {
- GString *err = g_string_new("");
- g_string_printf(err, "Error parsing SX [%s] credit formula [%s] at [%s]: %s",
- xaccSchedXactionGetName(createUD->tci->parentTCT->sx),
- str, parseErrorLoc, gnc_exp_parser_error_string());
- *createUD->creation_errors = g_list_append(*createUD->creation_errors, err);
- credit_num = gnc_numeric_create( 0, 1 );
- }
- }
-
- kvp_val = kvp_frame_get_slot_path( split_kvpf,
- GNC_SX_ID,
- GNC_SX_DEBIT_FORMULA,
- NULL);
- str = kvp_value_get_string( kvp_val );
-
- debit_num = gnc_numeric_create( 0, 1 );
- if (str != NULL && strlen(str) != 0) {
- if (!gnc_exp_parser_parse_separate_vars(str, &debit_num,
- &parseErrorLoc,
- actualVars))
- {
- GString *err = g_string_new("");
- g_string_printf(err, "Error parsing SX [%s] debit formula [%s] at [%s]: %s",
- xaccSchedXactionGetName(createUD->tci->parentTCT->sx),
- str, parseErrorLoc, gnc_exp_parser_error_string());
- *createUD->creation_errors = g_list_append(*createUD->creation_errors, err);
- debit_num = gnc_numeric_create( 0, 1 );
- }
-
- }
-
- final = gnc_numeric_sub_fixed( debit_num, credit_num );
-
- gncn_error = gnc_numeric_check(final);
- if (gncn_error != GNC_ERROR_OK) {
- GString *err = g_string_new("");
- g_string_printf(err, "Error %d in SX [%s] final gnc_numeric value, using 0 instead.",
- gncn_error,
- xaccSchedXactionGetName(createUD->tci->parentTCT->sx));
- *createUD->creation_errors = g_list_append(*createUD->creation_errors, err);
- final = gnc_numeric_create(0, 1);
- }
-
- xaccSplitSetValue(split, final);
- if (! gnc_commodity_equal(split_cmdty, first_cmdty))
- {
- GString *exchange_rate_var_name = g_string_sized_new(16);
- gnc_numeric *exchange, amt;
-
- /*
- GNCPriceDB *price_db = gnc_pricedb_get_db(gnc_get_current_book());
- GNCPrice *price;
-
- price = gnc_pricedb_lookup_latest(price_db, first_cmdty, split_cmdty);
- if (price == NULL)
- {
- price = gnc_pricedb_lookup_latest(price_db, split_cmdty, first_cmdty);
- if (price == NULL)
- {
- GString *err = g_string_new("");
- g_string_printf(err, "could not find pricedb entry for commodity-pair (%s, %s).",
- gnc_commodity_get_mnemonic(first_cmdty),
- gnc_commodity_get_mnemonic(split_cmdty));
- exchange = gnc_numeric_create(1, 1);
- *createUD->creation_errors = g_list_append(*createUD->creation_errors, err);
-
- }
- else
- {
- exchange = gnc_numeric_div(gnc_numeric_create(1,1),
- gnc_price_get_value(price),
- 1000, GNC_HOW_RND_ROUND);
- }
- }
- else
- {
- exchange = gnc_price_get_value(price);
- }
- */
-
- g_string_printf(exchange_rate_var_name, "%s -> %s",
- gnc_commodity_get_mnemonic(split_cmdty),
- gnc_commodity_get_mnemonic(first_cmdty));
- exchange = (gnc_numeric*)g_hash_table_lookup(actualVars, exchange_rate_var_name->str);
- if (exchange == NULL)
- {
- exchange = g_new0(gnc_numeric, 1);
- *exchange = gnc_numeric_create(0, 1);
- }
- g_string_free(exchange_rate_var_name, TRUE);
-
- amt = gnc_numeric_mul(final, *exchange, 1000, GNC_HOW_RND_ROUND);
- xaccSplitSetAmount(split, amt);
- }
- xaccSplitScrub( split );
- }
- xaccAccountCommitEdit( acct );
- }
-
- /* Cleanup actualVars table. */
- {
- g_hash_table_foreach( actualVars,
- gnc_sxsl_del_vars_table_ea,
- NULL );
- g_hash_table_destroy( actualVars );
- actualVars = NULL;
- }
-
- if (errFlag) {
- PERR("Some error in new transaction creation...");
- xaccTransDestroy(newT);
- xaccTransCommitEdit(newT);
- return 13;
- }
-
- {
- kvp_frame *txn_frame;
- /* set a kvp-frame element in the transaction indicating and
- * pointing-to the SX this was created from. */
- txn_frame = xaccTransGetSlots(newT);
- kvp_frame_set_guid(txn_frame, "from-sched-xaction",
- xaccSchedXactionGetGUID(tci->parentTCT->sx));
- }
-
- xaccTransCommitEdit(newT);
-
- if ( createUD->createdGUIDs != NULL ) {
- *createUD->createdGUIDs =
- g_list_append( *(createUD->createdGUIDs),
- (gpointer)xaccTransGetGUID(newT) );
- }
-
- return 0;
-}
-
-/**
- * This should be called with the dates in increasing order, or the last call
- * will set the last occur date incorrectly.
- **/
-static void
-create_transactions_on(SchedXaction *sx,
- GDate *gd,
- toCreateInstance *tci,
- GList **createdGUIDs,
- GList **creation_errors)
-{
- createData createUD;
- AccountGroup *ag;
- Account *acct;
- const char *id;
-
- if (tci) {
- g_assert(g_date_compare(gd, tci->date) == 0);
- }
-
- ag = gnc_book_get_template_group( gnc_get_current_book () );
- id = guid_to_string( xaccSchedXactionGetGUID(sx) );
- if ( !(ag && id) ) {
- return;
- }
- /* This looks strange but it's right. The account is
- named after the guid string. */
- acct = xaccGetAccountFromName( ag, id );
- if (!acct) {
- return;
- }
-
- createUD.tci = tci;
- createUD.createdGUIDs = createdGUIDs;
- createUD.creation_errors = creation_errors;
- xaccAccountForEachTransaction(acct,
- create_each_transaction_helper,
- /*tct*/ &createUD);
-}
-
-static void
-_hashToList( gpointer key, gpointer value, gpointer user_data )
-{
- *(GList**)user_data = g_list_append( *(GList**)user_data, key );
-}
-
-static void
-hash_to_sorted_list( GHashTable *hashTable, GList **gl )
-{
- g_hash_table_foreach( hashTable, _hashToList, gl );
- *gl = g_list_sort( *gl, g_str_equal );
-}
-
-static void
-clear_variable_numerics( gpointer key, gpointer value, gpointer data )
-{
- g_free( (gnc_numeric*)value );
- g_hash_table_insert( (GHashTable*)data, key, NULL );
-}
-
-static gint
-_get_vars_helper(Transaction *txn, void *var_hash_data)
-{
- GHashTable *var_hash = (GHashTable*)var_hash_data;
- GList *split_list;
- kvp_frame *kvpf;
- kvp_value *kvp_val;
- Split *s;
- char *str;
- gnc_commodity *first_cmdty = NULL;
-
- split_list = xaccTransGetSplitList(txn);
-
- if ( split_list == NULL ) {
- return 1;
- }
-
- for ( ; split_list ; split_list = split_list->next ) {
- gnc_commodity *split_cmdty = NULL;
- GUID *acct_guid;
- Account *acct;
-
- s = (Split*)split_list->data;
- kvpf = xaccSplitGetSlots(s);
- kvp_val = kvp_frame_get_slot_path(kvpf,
- GNC_SX_ID,
- GNC_SX_ACCOUNT,
- NULL);
- acct_guid = kvp_value_get_guid( kvp_val );
- acct = xaccAccountLookup( acct_guid, gnc_get_current_book ());
- split_cmdty = xaccAccountGetCommodity(acct);
- if (first_cmdty == NULL)
- {
- first_cmdty = split_cmdty;
- }
-
- if (! gnc_commodity_equal(split_cmdty, first_cmdty))
- {
- gnc_numeric *tmp_num;
- GString *var_name = g_string_sized_new(16);
- g_string_printf(var_name, "%s -> %s",
- gnc_commodity_get_mnemonic(split_cmdty),
- gnc_commodity_get_mnemonic(first_cmdty));
- tmp_num = g_new0(gnc_numeric, 1);
- *tmp_num = gnc_numeric_create(0, 1);
- g_hash_table_insert(var_hash, g_strdup(var_name->str), tmp_num);
- g_string_free(var_name, TRUE);
- }
-
- // existing... ------------------------------------------
-
- kvp_val = kvp_frame_get_slot_path( kvpf,
- GNC_SX_ID,
- GNC_SX_CREDIT_FORMULA,
- NULL);
- if ( kvp_val != NULL ) {
- str = kvp_value_get_string( kvp_val );
- if ( str && strlen(str) != 0 ) {
- parse_vars_from_formula( str, var_hash, NULL );
- }
- }
-
- kvp_val = kvp_frame_get_slot_path( kvpf,
- GNC_SX_ID,
- GNC_SX_DEBIT_FORMULA,
- NULL);
- if ( kvp_val != NULL ) {
- str = kvp_value_get_string( kvp_val );
- if ( str && strlen(str) != 0 ) {
- parse_vars_from_formula( str, var_hash, NULL );
- }
- }
- }
-
- return 0;
-}
-
-void
-sxsl_get_sx_vars( SchedXaction *sx, GHashTable *var_hash )
-{
- AccountGroup *ag;
- Account *acct;
- const char *id;
-
- ag = gnc_book_get_template_group( gnc_get_current_book () );
- id = guid_to_string( xaccSchedXactionGetGUID(sx) );
- /* Get account named after guid string. */
- acct = xaccGetAccountFromName( ag, id );
- xaccAccountForEachTransaction(acct,
- _get_vars_helper,
- var_hash);
-
- g_hash_table_foreach( var_hash,
- clear_variable_numerics,
- (gpointer)var_hash );
-}
-
-static gboolean
-tct_table_entry_key_handle( GtkWidget *widget, GdkEventKey *event, gpointer ud )
-{
- gnc_numeric *num;
- GtkEntry *ent = NULL;
- GString *str;
-
- if ( (event->keyval != GDK_Tab)
- && (event->keyval != GDK_ISO_Left_Tab) ) {
- return FALSE;
- }
-
- /* First, deal with formulas in these cells, replacing their
- * contents with the eval'd value. */
- ent = GTK_ENTRY(widget);
- num = (gnc_numeric*)g_object_get_data( G_OBJECT(ent), "numeric" );
- str = g_string_new("");
- g_string_printf( str, "%0.2f", gnc_numeric_to_double( *num ) );
- gtk_entry_set_text( ent, str->str );
- g_string_free( str, TRUE );
-
- /* FIXME: Next, deal with tab-ordering in this page...
- *
- * if ( entry isn't last in table )
- * return (normal)FALSE
- * if ( unfilled entry in this table exists )
- * change focus to unfilled entry
- * if ( no more unfilled clist-rows )
- * return (normal)FALSE
- * clist-select next unfilled row
- *
- * This doesn't deal with shift-tab very well ...
- * And there's a question of if the user will allow us to futz with
- * their tab-ordering... though it's already pretty screwed up for the
- * dynamically-changing-table anyways, so they probably won't mind
- * too much... -- jsled
- */
-
- return FALSE;
-}
-
-static
-void
-sxsincelast_tc_row_sel( GtkCTree *ct,
- GList *nodelist,
- gint column,
- gpointer user_data)
-{
- static const int NUM_COLS = 2;
- static GtkAttachOptions sopts = GTK_SHRINK;
- static GtkAttachOptions lxopts = GTK_EXPAND | GTK_FILL;
- GtkTable *varTable;
- int tableIdx;
- GtkWidget *label, *entry;
- GList *varList;
- gint varHashSize;
- GtkCTreeNode *node = GTK_CTREE_NODE( nodelist );
-
- toCreateInstance *tci;
- sxSinceLastData *sxsld;
-
- /* FIXME: this should more gracefully deal with multiple 'row-select'
- * signals from double/triple-clicks. */
- sxsld = (sxSinceLastData*)user_data;
-
- tci = (toCreateInstance*)gtk_ctree_node_get_row_data( ct, node );
- if ( !tci )
- return;
-
- sxsld->curSelTCI = tci;
- sxsld_set_sensitive_tci_controls( sxsld, TRUE );
- /* set real sensitivity based on the state of the TCI; when we change
- * the option menu selection here, it won't fire the selection-done
- * handler, so we have to force it. */
-
- {
- GtkOptionMenu *optMenu;
-
- optMenu = GTK_OPTION_MENU(
- glade_xml_get_widget( sxsld->gxml,
- SX_DISPOSITION_OPT ) );
- gtk_option_menu_set_history( optMenu,
- sxsld->curSelTCI->state );
- sxsld_disposition_changed( GTK_MENU_SHELL(
- gtk_option_menu_get_menu( optMenu ) ),
- sxsld );
- }
-
- /* Setup the query for the to-create register to only show the
- * transaction[s] associated with this lineitem. */
- {
- AccountGroup *ag;
- Account *acct;
- Query *q;
- const gchar *sxGUIDstr;
- SplitRegister *sr;
-
- q = xaccMallocQuery();
- xaccQuerySetBook( q, gnc_get_current_book() );
- ag = gnc_book_get_template_group( gnc_get_current_book() );
- sxGUIDstr = guid_to_string( xaccSchedXactionGetGUID( tci->parentTCT->sx ) );
- acct = xaccGetAccountFromName( ag, sxGUIDstr );
- g_assert( acct != NULL );
- xaccQueryAddSingleAccountMatch( q, acct, QUERY_AND );
-
- gnc_suspend_gui_refresh();
- gnc_ledger_display_set_query( sxsld->to_create_ledger, q );
- sr = gnc_ledger_display_get_split_register( sxsld->to_create_ledger );
- gnc_split_register_set_template_account( sr, acct );
- gnc_ledger_display_refresh( sxsld->to_create_ledger );
- gnc_resume_gui_refresh();
- }
-
- /* Get the count of variables; potentially remove the system-defined
- * variables if they're present in the expression. */
- varHashSize = g_hash_table_size( tci->varBindings );
- {
- gpointer *unusedKey, *unusedVal;
- if ( g_hash_table_lookup_extended( tci->varBindings, "i",
- (gpointer)&unusedKey,
- (gpointer)&unusedVal ) ) {
- varHashSize -= 1;
- }
- }
-
- if ( varHashSize == 0 ) {
- return;
- }
-
- varList = NULL;
- hash_to_sorted_list( tci->varBindings, &varList );
- varTable = GTK_TABLE( glade_xml_get_widget( sxsld->gxml,
- VARIABLE_TABLE ) );
- gtk_table_resize( varTable, varHashSize + 1, NUM_COLS );
-
- tableIdx = 1;
- for ( ; varList ; varList = varList->next ) {
- gchar *varName;
- GString *gstr;
- const gchar *numValueStr;
- gnc_numeric *numValue, *tmpNumValue;
-
- varName = (gchar*)varList->data;
- if ( strcmp( varName, "i" ) == 0 ) {
- continue;
- }
-
- gstr = g_string_sized_new(16);
- g_string_printf( gstr, "%s: ", varName );
- label = gtk_label_new( gstr->str );
- gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_RIGHT );
- g_string_free( gstr, TRUE );
-
- entry = gtk_entry_new();
- g_object_set_data( G_OBJECT(entry), "varName", varName );
- g_object_set_data( G_OBJECT(entry), "tci", tci );
- tmpNumValue = g_new0( gnc_numeric, 1 );
- *tmpNumValue = gnc_numeric_create( 0, 1 );
- g_object_set_data( G_OBJECT(entry), "numeric", tmpNumValue );
- if ( tableIdx == varHashSize ) {
- /* Set a flag so we can know if we're the last row of
- * the table. */
- g_object_set_data( G_OBJECT(entry), "lastVisualElt",
- (gpointer)1 );
- }
-
- gtk_widget_set_size_request( entry, 64, -1 );
- numValue = (gnc_numeric*)g_hash_table_lookup( tci->varBindings,
- varName );
- if ( numValue != NULL ) {
- numValueStr =
- xaccPrintAmount( *numValue,
- gnc_default_print_info( FALSE ) );
- gtk_entry_set_text( GTK_ENTRY(entry), numValueStr );
- }
-
- /* fixme::2002.02.10 jsled testing */
- g_signal_connect( entry, "key-press-event",
- G_CALLBACK( tct_table_entry_key_handle ),
- NULL );
- g_signal_connect( entry, "changed",
- G_CALLBACK( sxsincelast_entry_changed ),
- sxsld );
- g_signal_connect( entry, "destroy",
- G_CALLBACK(gnc_sxsld_free_entry_numeric),
- sxsld );
-
- gtk_table_attach( varTable, label,
- 0, 1, tableIdx, tableIdx + 1,
- lxopts, sopts, 0, 0 );
- gtk_table_attach( varTable, entry,
- 1, 2, tableIdx, tableIdx + 1,
- sopts, sopts, 0, 0 );
- tableIdx += 1;
- }
-
- gtk_widget_show_all( GTK_WIDGET(varTable) );
-}
-
-static void
-clean_variable_table( sxSinceLastData *sxsld )
-{
- GtkTable *table;
- GList *children, *toFree, *l;
- GtkTableChild *child;
-
- table = GTK_TABLE( glade_xml_get_widget( sxsld->gxml,
- VARIABLE_TABLE ) );
- children = table->children;
- g_assert( children );
-
- toFree = NULL;
- for( ; children ; children = children->next ) {
- /* Destroy all children after the first [label-continaing]
- row... ie, leave the labels in place. */
- child = (GtkTableChild*)children->data;
- if ( child->top_attach > 0 ) {
- toFree = g_list_append( toFree, child->widget );
- }
- }
-
- gtk_table_resize( table, 1, 2 );
-
- for ( l = toFree; l; l = l->next ) {
- gtk_widget_destroy( (GtkWidget*)l->data );
- }
- g_list_free( toFree );
-}
-
-static void
-sxsincelast_tc_row_unsel( GtkCTree *ct,
- GList *nodelist,
- gint column,
- gpointer user_data)
-{
- sxSinceLastData *sxsld;
-
- sxsld = (sxSinceLastData*)user_data;
- clean_variable_table( sxsld );
-
- sxsld->curSelTCI = NULL;
-
- sxsld_set_sensitive_tci_controls( sxsld, FALSE );
-
- {
- Query *q;
- q = xaccMallocQuery();
- xaccQueryClear( q );
- gnc_suspend_gui_refresh();
- gnc_ledger_display_set_query( sxsld->to_create_ledger, q );
- gnc_ledger_display_refresh( sxsld->to_create_ledger );
- gnc_resume_gui_refresh();
- }
-
-
- /* we cleanup the gnc_numerics we allocated in the "destroy" signal
- * handler of the entry [where we attached them] */
-}
-
-void
-print_vars_helper( gpointer key, gpointer value, gpointer user_data )
-{
- DEBUG( "\"%s\" -> %.8x [%s]",
- (gchar*)key, GPOINTER_TO_UINT(value),
- gnc_numeric_to_string( *(gnc_numeric*)value ) );
-}
-
-int
-parse_vars_from_formula( const char *formula,
- GHashTable *varHash,
- gnc_numeric *result )
-{
- gnc_numeric *num;
- char *errLoc;
- int toRet;
-
- if ( result ) {
- num = result;
- } else {
- num = g_new0( gnc_numeric, 1 );
- }
-
- toRet = 0;
- if ( ! gnc_exp_parser_parse_separate_vars( formula, num,
- &errLoc, varHash ) ) {
- toRet = -1;
- }
-
- if ( !result ) {
- g_free( num );
- }
- return toRet;
-}
-
-/**
- * The following makes me [jsled] somewhat sad, but it works... :I
- *
- * Basic problem: You can't create a SX instance if any after it have already
- * been created [e.g., if an SX has instances on d_0, d_1 and d_2, and you
- * create d_0 and d_2, then d_1 will never get created ... only d_3, d_4,
- * &c.]
- *
- * This code, then, makes sure that the user hasn't skipped a date...
- *
- * Code flow...
- * . If non-consecutive Reminders chosen, disallow.
- * . Else, for each selected reminder, add to to-create list.
- * . Dismiss dialog.
- *
- * While we're doing this, we handle any previously-selected, now-unselected
- * reminders.
- *
- * Returns TRUE if there are processed, valid reminders... FALSE otherwise.
- **/
-static gboolean
-processed_valid_reminders_listP( sxSinceLastData *sxsld )
-{
- reminderTuple *rt;
- reminderInstanceTuple *rit;
- char *rtName;
- gboolean overallOkFlag, okFlag, prevState;
- GList *reminderList;
- GList *reminderInstList;
- GList *badList;
- GList *badRecentRun;
- GList *goodList;
- GList *toRevertList;
-
- rtName = NULL;
- goodList = NULL;
- overallOkFlag = TRUE;
-
- okFlag = prevState = TRUE;
- badList = badRecentRun = NULL;
- rt = NULL;
- toRevertList = NULL;
-
- for ( reminderList = sxsld->reminderList;
- reminderList;
- reminderList = reminderList->next ) {
-
- rt = (reminderTuple*)reminderList->data;
- okFlag = prevState = TRUE;
- badList = badRecentRun = NULL;
- rtName = xaccSchedXactionGetName( rt->sx );
-
- for ( reminderInstList = rt->instanceList;
- reminderInstList;
- reminderInstList = reminderInstList->next ) {
- rit = (reminderInstanceTuple*)reminderInstList->data;
-
- /* If we've previously created this RIT and now it's
- * not selected, then prepare to revert it
- * [later]. */
- if ( !rit->isSelected
- && rit->resultantTCI ) {
- toRevertList = g_list_append( toRevertList, rit );
- }
-
- if ( prevState ) {
- prevState = rit->isSelected;
- if ( !prevState ) {
- badRecentRun = g_list_append( badRecentRun, rit );
- }
- } else {
- if ( rit->isSelected ) {
- okFlag = FALSE;
- if ( g_list_length( badRecentRun ) > 0 ) {
- badList = g_list_concat( badList,
- badRecentRun );
- badRecentRun = NULL;
- }
- } else {
- badRecentRun =
- g_list_append( badRecentRun, rit );
- }
- }
- }
- overallOkFlag &=
- inform_or_add( sxsld, rt, okFlag, badList, &goodList );
- if ( badList ) {
- g_list_free( badList );
- badList = NULL;
- }
- if ( badRecentRun ) {
- g_list_free( badRecentRun );
- badRecentRun = NULL;
- }
- }
-
- /* Handle implications of above logic. */
- if ( !overallOkFlag ) {
- g_list_free( goodList );
- goodList = NULL;
-
- g_list_free( toRevertList );
- toRevertList = NULL;
-
- return FALSE;
- }
-
- if ( g_list_length( goodList ) > 0 ) {
- processSelectedReminderList( goodList, sxsld );
- g_list_free( goodList );
- goodList = NULL;
- }
-
- /* Revert the previously-created and now-unselected RITs. */
- gnc_sxsld_revert_reminders( sxsld, toRevertList );
- g_list_free( toRevertList );
- toRevertList = NULL;
-
- return TRUE;
-}
-
-
-/**
- * Remove the TCI from it's parent TCT, deleting any created transactions as
- * appropriate. Note: if after removing a TCIs from it's TCT and there are no
- * more instances in the TCT, then the TCT wouldn't have been created except
- * for us, and should be removed itself; we handle this as well.
- **/
-static
-void
-gnc_sxsld_revert_reminders( sxSinceLastData *sxsld,
- GList *toRevertList )
-{
- reminderInstanceTuple *rit;
- toCreateInstance *tci;
- toCreateTuple *tct;
- gboolean autoCreateState, notifyState;
- GList *l, *m;
-
- if ( !toRevertList ) {
- return;
- }
-
- for ( l = toRevertList; l; l = l->next ) {
- /* Navigate to the relevant objects. */
- rit = (reminderInstanceTuple*)l->data;
- g_assert( rit );
- tci = rit->resultantTCI;
- g_assert( tci );
- tct = tci->parentTCT;
- g_assert( tct );
-
- tct->instanceList = g_list_remove( tct->instanceList, tci );
-
- if ( g_list_length(tct->instanceList) == 0 ) {
- GList **correctList;
- /* if there are no instances, remove the TCT as
- * well. */
- xaccSchedXactionGetAutoCreate( rit->parentRT->sx,
- &autoCreateState,
- ¬ifyState );
- correctList = NULL;
- if ( autoCreateState ) {
- if ( notifyState ) {
- correctList = &sxsld->autoCreateList;
- }
- } else {
- correctList = &sxsld->toCreateList;
- }
-
- if ( correctList )
- *correctList = g_list_remove( *correctList, tct );
- }
-
- /* destroy any created transactions. */
- gnc_suspend_gui_refresh();
- for ( m = tci->createdTxnGUIDs; m; m = m->next ) {
- Transaction *t;
-
- sxsld->createdTxnGUIDList =
- g_list_remove( sxsld->createdTxnGUIDList,
- (GUID*)m->data );
- t = xaccTransLookup( (GUID*)m->data,
- gnc_get_current_book() );
- g_assert( t );
- xaccTransBeginEdit(t);
- xaccTransDestroy(t);
- xaccTransCommitEdit(t);
-
- }
- gnc_resume_gui_refresh();
-
- /* Free the now-dead TCI; this is buggy and causing
- * problems... */
- gnc_sxsld_free_tci( tci );
- rit->resultantTCI = NULL;
- }
-}
-
-
-static void
-sxsld_remind_row_toggle( GtkCTree *ct, GList *node,
- gint column, gpointer user_data )
-{
- GtkCTreeNode *ctn;
- reminderInstanceTuple *rit;
- sxSinceLastData *sxsld = (sxSinceLastData*)user_data;
- GnomeDruidPage *thisPage, *nextPage;
-
- ctn = GTK_CTREE_NODE( node );
- rit = (reminderInstanceTuple*)gtk_ctree_node_get_row_data( ct, ctn );
- if ( rit == NULL ) {
- PERR( "We got called to toggle a row that "
- "we can't find data for..." );
- return;
- }
- rit->isSelected = !rit->isSelected;
-
- /* Deal with setting up a correct next/finish button for this
- * page. */
- sxsld->remindSelCount += ( rit->isSelected ? 1 : -1 );
- thisPage = GNOME_DRUID_PAGE(glade_xml_get_widget( sxsld->gxml, REMINDERS_PG ));
- nextPage = gnc_sxsld_get_appropriate_page( sxsld, thisPage, FORWARD );
- if ( sxsld->remindSelCount == 0
- || sxsld->remindSelCount == 1 ) {
- /* If we don't have anywhere to go [read: there's only
- * reminders as of yet], and we've selected no reminders. */
-
- /* FIXME: damnit, this won't work correctly as we really want
- * to incorporate the effect of changing the reminder
- * selections into this, too. */
-
- gnome_druid_set_show_finish( sxsld->sincelast_druid,
- ( !nextPage
- && (sxsld->remindSelCount == 0) ) );
-
- } /* else { This else intentionally left blank; if it's >1, then we
- * handled the 'next/finish' button on the 0 -> 1 transition. } */
-}
-
-static
-void
-sxsld_obsolete_row_toggle( GtkCList *cl, gint row, gint col,
- GdkEventButton *event, gpointer ud )
-{
- toDeleteTuple *tdt;
-
- tdt = (toDeleteTuple*)gtk_clist_get_row_data( cl, row );
- tdt->isSelected = !tdt->isSelected;
-}
-
-/**
- * @return the count of created transactions which would be true after
- * processing the currently-selected state of to-create transactions. Note
- * that this includes auto-created transactions, which aren't shown in the
- * post-to-create review page.
- **/
-static
-gint
-sxsld_get_future_created_txn_count( sxSinceLastData *sxsld )
-{
- GList *tctList, *tciList;
- /* Get a reasonable initial count to modify below. */
- gint toRet = g_list_length( sxsld->createdTxnGUIDList );
-
- for ( tctList = sxsld->toCreateList;
- tctList; tctList = tctList->next ) {
-
- toCreateTuple *tct = (toCreateTuple*)tctList->data;
-
- for ( tciList = tct->instanceList;
- tciList;
- tciList = tciList->next ) {
-
- GList *txnSet, *splitList;
- toCreateInstance *tci = (toCreateInstance*)tciList->data;
-
- if ( tci->state == tci->prevState ) {
- continue;
- }
-
- switch ( tci->state ) {
- case SX_TO_CREATE:
- /* We were postpone or ignore, before ... so
- * add the new txns in. */
-
- /* Calculate the size of the transaction-list to be created. */
- txnSet = NULL;
- splitList = xaccSchedXactionGetSplits( tci->parentTCT->sx );
- for ( ; splitList; splitList = splitList->next ) {
- Split *s = (Split*)splitList->data;
- if ( g_list_find( txnSet, xaccSplitGetParent(s) ) == NULL ) {
- txnSet = g_list_append( txnSet, (gpointer)s );
- }
- }
- toRet += g_list_length( txnSet );
- g_list_free( txnSet );
- txnSet = NULL;
- break;
- case SX_IGNORE:
- case SX_POSTPONE:
- /* We were {postpone,ignore} or to-create,
- * before, so either continue to ignore or
- * subtract out the txns. */
- if ( tci->prevState != SX_TO_CREATE ) {
- continue;
- }
- toRet -= g_list_length( tci->createdTxnGUIDs );
- break;
- case SX_UNDEF:
- case SX_MAX_STATE:
- g_assert( "We shouldn't see any of these." );
- break;
- }
- }
- }
- g_assert( toRet >= 0 );
- return toRet;
-}
-
-static
-void
-sxsld_disposition_changed( GtkMenuShell *b, gpointer d )
-{
- sxSinceLastData *sxsld = (sxSinceLastData*)d;
- ToCreateState newState;
- gboolean newSensitivity;
- GtkCTree *ct;
- char *newCtreeText;
-
- newState =
- gnc_option_menu_get_active(
- glade_xml_get_widget( sxsld->gxml,
- SX_DISPOSITION_OPT ));
- /* Change the state of the TCI */
- //g_assert( sxsld->curSelTCI != NULL );
- g_return_if_fail(sxsld->curSelTCI != NULL);
-
- sxsld->curSelTCI->state = newState;
-
- newSensitivity = TRUE;
- newCtreeText = "FIXME";
-
- switch ( newState ) {
- case SX_TO_CREATE:
- newSensitivity = TRUE;
- {
- gboolean allVarsBound = TRUE;
- /* If there are no un-bound variables, then set the 'ready-to-go'
- flag to 'y'. */
- g_hash_table_foreach( sxsld->curSelTCI->varBindings,
- andequal_numerics_set,
- &allVarsBound );
- newCtreeText = ( allVarsBound
- ? _( READY_TEXT )
- : _( NEEDS_BINDINGS_TEXT ) );
- }
- break;
- case SX_IGNORE:
- newSensitivity = FALSE;
- newCtreeText = _( IGNORE_TEXT );
- break;
- case SX_POSTPONE:
- newSensitivity = FALSE;
- newCtreeText = _( POSTPONE_TEXT );
- break;
- default:
- g_assert( FALSE );
- break;
- }
-
- gtk_widget_set_sensitive( glade_xml_get_widget( sxsld->gxml,
- VARIABLE_TABLE ),
- newSensitivity );
- ct = GTK_CTREE(glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ));
- gtk_ctree_node_set_text( ct, sxsld->curSelTCI->node, 1, newCtreeText );
-
- /* set the 'next/finish' button appropraitely based on the new
- * selection. */
- gnome_druid_set_show_finish( sxsld->sincelast_druid,
- ( ( sxsld_get_future_created_txn_count(sxsld)
- - sxsld->autoCreatedCount )== 0 ) );
-}
-
-/**
- * Makes both the variable table and disposition selection [in]sensitive, as
- * specified.
- **/
-static
-void
-sxsld_set_sensitive_tci_controls( sxSinceLastData *sxsld,
- gboolean sensitive )
-{
- GtkWidget *w;
- w = glade_xml_get_widget( sxsld->gxml, SX_DISPOSITION_OPT );
- gtk_widget_set_sensitive( w, sensitive );
- w = glade_xml_get_widget( sxsld->gxml, VARIABLE_TABLE );
- gtk_widget_set_sensitive( w, sensitive );
-}
-
-static void
-create_bad_reminders_msg( gpointer data, gpointer ud )
-{
- GString *msg;
- reminderInstanceTuple *rit;
- static char tmpBuf[ MAX_DATE_LENGTH+1 ];
-
- rit = (reminderInstanceTuple*)data;
- msg = (GString*)ud;
- qof_print_gdate( tmpBuf, MAX_DATE_LENGTH, rit->occurDate );
- g_string_append_printf( msg, tmpBuf );
- g_string_append_printf( msg, "\n" );
-}
-
-static gboolean
-inform_or_add( sxSinceLastData *sxsld, reminderTuple *rt, gboolean okFlag,
- GList *badList, GList **goodList )
-{
- reminderInstanceTuple *rit;
- GList *instances;
- GString *userMsg;
-
- userMsg = NULL;
-
- if ( okFlag ) {
- /* Add selected instances of this rt to
- * okay-to-add-to-toCreateList list. */
- for ( instances = rt->instanceList;
- instances;
- instances = instances->next ) {
- rit = (reminderInstanceTuple*)instances->data;
- /* this isn't really all that efficient. */
- if ( rit->isSelected ) {
- *goodList = g_list_append( *goodList, rit );
- }
- }
- } else {
- /* [Add to list for later] dialog issuance to user. */
-
- userMsg = g_string_sized_new( 128 );
- g_string_printf( userMsg,
- "You cannot skip instances of "
- "Scheduled Transactions. "
- "The following instances of \"%s\" "
- "must be selected as well:\n\n",
- xaccSchedXactionGetName( rt->sx ) );
- g_list_foreach( badList, create_bad_reminders_msg, userMsg );
- gnc_error_dialog( sxsld->sincelast_window, userMsg->str );
- g_string_free( userMsg, TRUE );
- }
-
- return okFlag;
-}
-
-static void
-sx_obsolete_select_all_clicked(GtkButton *button, gpointer user_data)
-{
- sxSinceLastData* sxsld = user_data;
-
- GtkCList *ob_clist = GTK_CLIST(glade_xml_get_widget(sxsld->gxml,
- SX_OBSOLETE_CLIST));
- gtk_clist_select_all( ob_clist );
-}
-
-static void
-sx_obsolete_unselect_all_clicked(GtkButton *button, gpointer user_data)
-{
- sxSinceLastData* sxsld = user_data;
-
- GtkCList *ob_clist = GTK_CLIST(glade_xml_get_widget(sxsld->gxml,
- SX_OBSOLETE_CLIST));
- gtk_clist_unselect_all( ob_clist );
-}
-
-static void
-create_autoCreate_ledger( sxSinceLastData *sxsld )
-{
- SplitRegister *splitreg;
- GtkWidget *vbox;
- Query *q;
-
- q = xaccMallocQuery();
- xaccQuerySetBook (q, gnc_get_current_book ());
- sxsld->ac_ledger = gnc_ledger_display_query( q,
- GENERAL_LEDGER,
- REG_STYLE_LEDGER );
-
- /* First the embedded window */
- vbox = glade_xml_get_widget( sxsld->gxml, AUTO_CREATE_VBOX );
- sxsld->ac_window =
- gnc_embedded_window_new("SXWindowActions",
- gnc_sxsld_menu_entries,
- gnc_sxsld_menu_n_entries,
- "gnc-sxed-window-ui.xml",
- sxsld->sincelast_window,
- FALSE, /* no accelerators */
- sxsld);
- gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET(sxsld->ac_window),
- TRUE, TRUE, 0);
-
- /* Then the register in it */
- sxsld->ac_register = gnc_plugin_page_register_new_ledger(sxsld->ac_ledger);
- gnc_plugin_page_set_ui_description (sxsld->ac_register,
- "gnc-plugin-page-sxregister-ui.xml");
- gnc_plugin_page_register_set_options (sxsld->ac_register,
- NULL, NULL, 4, FALSE);
- gnc_embedded_window_open_page (sxsld->ac_window, sxsld->ac_register);
-
- /* Now configure the register */
- splitreg = gnc_ledger_display_get_split_register( sxsld->ac_ledger );
- gnc_split_register_config(splitreg,
- splitreg->type, splitreg->style,
- FALSE);
- gnc_split_register_show_present_divider( splitreg, FALSE );
-}
-
-static void
-create_created_ledger( sxSinceLastData *sxsld )
-{
- SplitRegister *splitreg;
- GtkWidget *vbox;
- Query *q;
-
- q = xaccMallocQuery();
- xaccQuerySetBook (q, gnc_get_current_book ());
- sxsld->created_ledger = gnc_ledger_display_query( q,
- GENERAL_LEDGER,
- REG_STYLE_LEDGER );
-
- /* First the embedded window */
- vbox = glade_xml_get_widget( sxsld->gxml, CREATED_VBOX );
- sxsld->created_window =
- gnc_embedded_window_new("SXWindowActions",
- gnc_sxsld_menu_entries,
- gnc_sxsld_menu_n_entries,
- "gnc-sxed-window-ui.xml",
- sxsld->sincelast_window,
- FALSE, /* no accelerators */
- sxsld);
- gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET(sxsld->created_window),
- TRUE, TRUE, 0);
-
- /* Then the register in it */
- sxsld->created_register = gnc_plugin_page_register_new_ledger(sxsld->created_ledger);
- gnc_plugin_page_set_ui_description (sxsld->created_register,
- "gnc-plugin-page-sxregister-ui.xml");
- gnc_plugin_page_register_set_options (sxsld->created_register,
- NULL, NULL, 4, FALSE);
- gnc_embedded_window_open_page (sxsld->created_window, sxsld->created_register);
-
- /* Now configure the register */
- splitreg = gnc_ledger_display_get_split_register( sxsld->created_ledger );
- gnc_split_register_config(splitreg,
- splitreg->type, splitreg->style,
- FALSE);
- gnc_split_register_show_present_divider( splitreg, FALSE );
-}
-
-#if 0
-static
-void
-sxsld_jump_to_real_txn( GtkAction *action, sxSinceLastData *sxsld )
-{
- SplitRegister *reg;
- GNCSplitReg *gsr;
- Account *account;
- Account *leader;
- Split *split;
-
- reg = gnc_ledger_display_get_split_register(sxsld->to_create_ledger);
- gsr = gnc_ledger_display_get_user_data(sxsld->to_create_ledger);
-
- split = gnc_split_register_get_current_split (reg);
- if (split == NULL)
- return;
-
- {
- GUID *acct_guid;
- kvp_frame *split_kvpf;
- kvp_value *kvp_val;
-
- split_kvpf = xaccSplitGetSlots( split );
- kvp_val = kvp_frame_get_slot_path( split_kvpf,
- GNC_SX_ID,
- GNC_SX_ACCOUNT,
- NULL );
- if ( kvp_val == NULL ) {
- PERR( "Null kvp_val for account" );
- }
- acct_guid = kvp_value_get_guid( kvp_val );
- account = xaccAccountLookup( acct_guid,
- gnc_get_current_book ());
- }
-
- if (account == NULL)
- return;
-
- leader = gnc_ledger_display_leader( gsr->ledger );
-
- if (account == leader)
- {
- split = xaccSplitGetOtherSplit(split);
- if (split == NULL)
- return;
-
- account = xaccSplitGetAccount(split);
- if (account == NULL)
- return;
- if (account == leader)
- return;
- }
-
- {
- GncPluginPage *new_page;
- GNCSplitReg *gsr;
-
- new_page = gnc_plugin_page_register_new (account, FALSE);
- gnc_main_window_open_page (NULL, new_page);
- gsr = gnc_plugin_page_register_get_gsr (new_page);
- gnc_split_reg_jump_to_split(gsr, split);
- }
-
- g_signal_stop_emission_by_name(gsr, "jump");
-}
-#endif
-
-static void
-create_to_create_ledger( sxSinceLastData *sxsld )
-{
- SplitRegister *splitreg;
- GtkWidget *vbox;
- Query *q;
-
- sxsld->to_create_ledger = gnc_ledger_display_template_gl( NULL );
- q = xaccMallocQuery();
- xaccQueryClear( q );
- gnc_ledger_display_set_query( sxsld->to_create_ledger, q );
-
- /* First the embedded window */
- vbox = glade_xml_get_widget( sxsld->gxml, TO_CREATE_TXN_VBOX );
- sxsld->to_create_window =
- gnc_embedded_window_new("SXWindowActions",
- gnc_sxsld_menu_entries,
- gnc_sxsld_menu_n_entries,
- "gnc-sxed-to-create-window-ui.xml",
- sxsld->sincelast_window,
- FALSE, /* no accelerators */
- sxsld);
- gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET(sxsld->to_create_window),
- TRUE, TRUE, 0);
-
- /* Then the register in it */
- sxsld->to_create_register = gnc_plugin_page_register_new_ledger(sxsld->to_create_ledger);
- gnc_plugin_page_set_ui_description (sxsld->to_create_register,
- "gnc-sxed-to-create-window-ui.xml");
- gnc_plugin_page_register_set_options(sxsld->to_create_register,
- NULL, NULL, 4, TRUE);
- gnc_embedded_window_open_page (sxsld->to_create_window, sxsld->to_create_register);
-
- /* Now configure the register */
- splitreg = gnc_ledger_display_get_split_register( sxsld->to_create_ledger );
- gnc_split_register_config( splitreg, splitreg->type, splitreg->style,
- FALSE );
- gnc_split_register_show_present_divider( splitreg, FALSE );
-}
-
-static void
-clean_sincelast_data( sxSinceLastData *sxsld )
-{
- GList *l, *m;
-
- /* FIXME: handle the cloned state data for all the instance
- * structures. */
-
- /* Free the reminder list */
- for ( l = sxsld->reminderList; l; l = l->next ) {
- reminderTuple *rt;
- reminderInstanceTuple *rit;
-
- rt = (reminderTuple*)l->data;
- for ( m = rt->instanceList; m; m = m->next ) {
- rit = (reminderInstanceTuple*)m->data;
- g_date_free( rit->endDate );
- g_date_free( rit->occurDate );
- g_free( rit );
- }
- g_list_free( rt->instanceList );
- rt->instanceList = NULL;
- g_free( rt );
- }
- g_list_free( sxsld->reminderList );
-
- /* Free the auto-create and to-create lists */
- gnc_sxsld_free_toCreateTuple_list( sxsld->autoCreateList );
- g_list_free( sxsld->autoCreateList );
- sxsld->autoCreateList = NULL;
-
- gnc_sxsld_free_toCreateTuple_list( sxsld->toCreateList );
- g_list_free( sxsld->toCreateList );
- sxsld->toCreateList = NULL;
-
- /* Free the to-remove list */
- for ( l = sxsld->toRemoveList; l; l = l->next ) {
- toDeleteTuple *tdt;
-
- tdt = (toDeleteTuple*)l->data;
- g_date_free( tdt->endDate );
- tdt->endDate = NULL;
-
- g_free( tdt );
- }
- g_list_free( sxsld->toRemoveList );
- sxsld->toRemoveList = NULL;
-
- /* free the created-txn-guid list */
- g_list_free( sxsld->createdTxnGUIDList );
- sxsld->createdTxnGUIDList = NULL;
-
- /* Free the saved SX temporal states */
- g_hash_table_foreach( sxsld->sxInitStates,
- gnc_sxsld_free_sxState,
- NULL );
- g_hash_table_destroy( sxsld->sxInitStates );
- sxsld->sxInitStates = NULL;
-
-}
-
-static
-void
-gnc_sxsld_free_tci( toCreateInstance *tci )
-{
- if ( tci->date ) {
- g_date_free(tci->date);
- tci->date = NULL;
- }
-
- if ( tci->varBindings ) {
- g_hash_table_foreach( tci->varBindings,
- _free_varBindings_hash_elts,
- NULL );
- g_hash_table_destroy( tci->varBindings );
- tci->varBindings = NULL;
- }
-
- /* Handling these original/previous/current-stated things is painful,
- * but here's the rules...
- *
- * If we're not cancelling...
- * . If ignored, destroy.
- * . If postponed, DON'T destroy.
- * . If to-create, destroy.
- *
- * If we are cancelling...
- * . If ignored, destroy.
- * . If postponed, destroy.
- * . UNLESS previously postponed
- * . If to-create, destroy.
- *
- * So, we don't destroy postponed by default, and let the
- * cancel-specific case handle that destruction [thus the
- * valid-pointer check].
- */
- if ( tci->prevState != SX_POSTPONE
- && tci->origState != SX_POSTPONE
- && tci->sxStateData != NULL ) {
- gnc_sx_destroy_temporal_state( tci->sxStateData );
- tci->sxStateData = NULL;
- }
-
- tci->parentTCT = NULL;
-
- if ( tci->createdTxnGUIDs ) {
- g_list_free( tci->createdTxnGUIDs );
- tci->createdTxnGUIDs = NULL;
- }
-
- g_free( tci );
-}
-
-/**
- * Frees a list of toCreateTuples, like the autoCreateList and
- * toCreateList.
- **/
-static
-void
-gnc_sxsld_free_toCreateTuple_list( GList *l )
-{
- GList *m;
- toCreateTuple *tct;
-
- for ( ; l; l = l->next ) {
- tct = (toCreateTuple*)l->data;
- for ( m = tct->instanceList; m; m = m->next ) {
- gnc_sxsld_free_tci( (toCreateInstance*)m->data );
- }
- g_list_free( tct->instanceList );
- tct->instanceList = NULL;
- g_free( tct );
- }
-}
-
-static
-void
-gnc_sxsld_free_sxState( gpointer key,
- gpointer value,
- gpointer userdata )
-{
- gnc_sx_destroy_temporal_state( (void*)value );
-}
-
-static
-void
-gnc_sxsld_free_entry_numeric( GObject *o, gpointer ud )
-{
- gnc_numeric *num;
- num = (gnc_numeric*)g_object_get_data( o, "numeric" );
- g_free( num );
-}
-
-static
-void
-gnc_sxsld_commit_ledgers( sxSinceLastData *sxsld )
-{
- gnc_split_register_save(
- gnc_ledger_display_get_split_register(sxsld->created_ledger),
- TRUE );
- gnc_split_register_save(
- gnc_ledger_display_get_split_register(sxsld->ac_ledger),
- TRUE );
-}
-
-static
-void
-_adderror(gpointer data, gpointer user_data)
-{
- GString *dialog_text = (GString*)user_data;
- g_string_append_printf(dialog_text, "- %s\n", ((GString*)data)->str);
-}
-
-static
-void
-creation_errors_dialog(GList *creation_errors)
-{
- GString *dialog_text = g_string_new(_("The following errors were encountered while creating the Scheduled Transactions:\n"));
- g_list_foreach(creation_errors, (GFunc)_adderror, dialog_text);
- gnc_info_dialog(NULL, "%s", dialog_text->str);
- g_string_free(dialog_text, TRUE);
-}
-
-static void
-_free_creation_errors(gpointer data, gpointer user_data_unused)
-{
- g_string_free((GString*)data, TRUE);
-}
-
-static
-void
-creation_errors_free(GList *creation_errors)
-{
- g_list_foreach(creation_errors, (GFunc)_free_creation_errors, NULL);
- g_list_free(creation_errors);
-}
Deleted: gnucash/trunk/src/gnome/dialog-sxsincelast.h
===================================================================
--- gnucash/trunk/src/gnome/dialog-sxsincelast.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/dialog-sxsincelast.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,60 +0,0 @@
-/********************************************************************\
- * dialog-sxsincelast.h - SchedXaction "Since-Last-Run" dialog *
- * Copyright (c) 2001 Joshua Sled <jsled at asynchronous.org> *
- * *
- * 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 *
-\********************************************************************/
-
-#ifndef DIALOG_SXSINCELAST_H
-#define DIALOG_SXSINCELAST_H
-
-/**
- * @return The magnitude of the return value is the number of auto-created,
- * no-notification scheduled transactions created. This value is positive if
- * there are additionally other SXes which need user interaction and the
- * Druid has been displayed, or negative if there are not, and no Druid
- * window was realized. In the case where there the dialog has been
- * displayed but no auto-create-no-notify transactions have been created,
- * INT_MAX [limits.h] is returned. 0 is treated as negative, with no
- * transactions created and no dialog displayed. The caller can use this
- * value as appropriate to inform the user.
- *
- * [e.g., for book-open-hook: do nothing; for menu-selection: display an info
- * dialog stating there's nothing to do.]
- **/
-gint gnc_ui_sxsincelast_dialog_create( void );
-void gnc_sx_sxsincelast_book_opened (void);
-
-/**
- * Returns the varaibles from the Splits of the given SchedXaction as the
- * keys of the given GHashTable.
- **/
-void sxsl_get_sx_vars( SchedXaction *sx, GHashTable *varHash );
-
-/**
- * Returns the variables from the given formula [free-form non-numeric
- * character strings] as the keys of the given GHashTable.
- * @param result can be NULL if you're not interested in the result
- **/
-int parse_vars_from_formula( const char *formula,
- GHashTable *varHash,
- gnc_numeric *result );
-
-void print_vars_helper( gpointer key, gpointer value, gpointer user_data );
-
-#endif // !defined(DIALOG_SXSINCELAST_H)
Modified: gnucash/trunk/src/gnome/druid-loan.c
===================================================================
--- gnucash/trunk/src/gnome/druid-loan.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/druid-loan.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -35,7 +35,6 @@
#include "SchedXaction.h"
#include "SX-book.h"
-#include "SX-book-p.h"
#include "SX-ttinfo.h"
#include "druid-utils.h"
#include "gnc-book.h"
@@ -1982,7 +1981,8 @@
ld_create_sx_from_tcSX( LoanDruidData *ldd, toCreateSX *tcSX )
{
SchedXaction *sx;
- GList *ttxnList, *sxList;
+ SchedXactions *sxes;
+ GList *ttxnList;
sx = xaccSchedXactionMalloc( gnc_get_current_book() );
xaccSchedXactionSetName( sx, tcSX->name );
@@ -2003,9 +2003,8 @@
xaccSchedXactionSetTemplateTrans( sx, ttxnList,
gnc_get_current_book() );
- sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
- sxList = g_list_append( sxList, sx );
- gnc_book_set_schedxactions( gnc_get_current_book(), sxList );
+ sxes = gnc_book_get_schedxactions(gnc_get_current_book());
+ gnc_sxes_add_sx(sxes, sx);
g_list_free( ttxnList );
ttxnList = NULL;
Modified: gnucash/trunk/src/gnome/glade/sched-xact.glade
===================================================================
--- gnucash/trunk/src/gnome/glade/sched-xact.glade 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/glade/sched-xact.glade 2007-01-19 23:45:45 UTC (rev 15399)
@@ -77,7 +77,7 @@
</child>
<child>
- <widget class="GtkVBox" id="vbox105">
+ <widget class="GtkVBox" id="editor-vbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
@@ -2983,360 +2983,6 @@
</child>
</widget>
-<widget class="GtkDialog" id="Scheduled Transaction List">
- <property name="visible">True</property>
- <property name="title" translatable="yes">Scheduled Transactions</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="default_width">640</property>
- <property name="default_height">480</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox18">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area18">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="close_button">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-close</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label847992">
- <property name="visible">True</property>
- <property name="label" translatable="yes"><b>Transactions</b></property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkAlignment" id="alignment34">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox123">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
- <child>
- <widget class="GtkCList" id="sched_xact_list">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="n_columns">3</property>
- <property name="column_widths">127,140,80</property>
- <property name="selection_mode">GTK_SELECTION_SINGLE</property>
- <property name="show_titles">True</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
-
- <child>
- <widget class="GtkLabel" id="label847750">
- <property name="label" translatable="yes">Name</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label847751">
- <property name="label" translatable="yes">Frequency</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label847752">
- <property name="label" translatable="yes">Next Occurrence</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVButtonBox" id="vbuttonbox1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
- <property name="spacing">10</property>
-
- <child>
- <widget class="GtkButton" id="new_button">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-new</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="edit_button">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment24">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox179">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image1">
- <property name="visible">True</property>
- <property name="stock">gtk-properties</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label847980">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Edit</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="delete_button">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-delete</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label847993">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label847970">
- <property name="visible">True</property>
- <property name="label" translatable="yes"><b>Upcoming</b></property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkAlignment" id="alignment35">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="upcoming_cal_hbox">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <placeholder/>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
<widget class="GtkDialog" id="sx_from_real_trans">
<property name="visible">True</property>
<property name="title" translatable="yes">Make Scheduled Transaction</property>
@@ -6717,4 +6363,364 @@
</child>
</widget>
+<widget class="GtkWindow" id="sx list plugin page content">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+
+ <child>
+ <widget class="GtkVPaned" id="sx-list-vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox183">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label847992">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Transactions</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment34">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox123">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="sx_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">True</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="upcoming mumble">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label847993">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label847970">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Upcoming</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment35">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="upcoming_cal_hbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="since-last-run-dialog">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Since Last Run...</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">480</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox25">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area25">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="okbutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox182">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVPaned" id="paned">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">240</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow21">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="instance_view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox179">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkFixed" id="fixed1">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="review_txn_toggle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Review created transactions</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
</glade-interface>
Modified: gnucash/trunk/src/gnome/gnc-plugin-basic-commands.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-basic-commands.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/gnc-plugin-basic-commands.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -41,8 +41,7 @@
#include "dialog-chart-export.h"
#include "dialog-fincalc.h"
#include "dialog-find-transactions.h"
-#include "dialog-scheduledxaction.h"
-#include "dialog-sxsincelast.h"
+#include "dialog-sx-since-last-run.h"
#include "dialog-totd.h"
#include "druid-acct-period.h"
#include "druid-loan.h"
@@ -55,6 +54,8 @@
#include "gnc-window.h"
#include "gnc-session.h"
+#include "gnc-plugin-page-sx-list.h"
+
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_GUI;
@@ -434,35 +435,50 @@
static void
gnc_main_window_cmd_actions_scheduled_transaction_editor (GtkAction *action, GncMainWindowActionData *data)
{
- gnc_ui_scheduled_xaction_dialog_create ();
+ GncPluginPage *page = gnc_plugin_page_sx_list_new();
+ gnc_main_window_open_page(NULL, page);
}
static void
gnc_main_window_cmd_actions_since_last_run (GtkAction *action, GncMainWindowActionData *data)
{
GncMainWindow *window;
- gint ret;
+ GncSxInstanceModel *sx_instances;
+ GncSxSummary summary;
const char *nothing_to_do_msg =
_( "There are no Scheduled Transactions to be entered at this time." );
g_return_if_fail (data != NULL);
window = data->window;
- ret = gnc_ui_sxsincelast_dialog_create ();
- if ( ret == 0 ) {
- gnc_info_dialog (GTK_WIDGET(&window->gtk_window), nothing_to_do_msg);
- } else if ( ret < 0 ) {
- gnc_info_dialog (GTK_WIDGET(&window->gtk_window), ngettext
- /* Translators: %d is the number of transactions. This is a
- ngettext(3) message. */
- ("There are no Scheduled Transactions to be entered at this time. "
- "(%d transaction automatically created)",
- "There are no Scheduled Transactions to be entered at this time. "
- "(%d transactions automatically created)",
- -(ret)),
- -(ret));
- } /* else { this else [>0 means dialog was created] intentionally left
- * blank. } */
+
+ sx_instances = gnc_sx_get_current_instances();
+ gnc_sx_instance_model_summarize(sx_instances, &summary);
+ gnc_sx_instance_model_effect_change(sx_instances, TRUE, NULL, NULL);
+ if (summary.need_dialog)
+ {
+ gnc_ui_sx_since_last_run_dialog(sx_instances);
+ }
+ else
+ {
+ if (summary.num_auto_create_no_notify_instances == 0)
+ {
+ gnc_info_dialog(GTK_WIDGET(&window->gtk_window), nothing_to_do_msg);
+ }
+ else
+ {
+ gnc_info_dialog(GTK_WIDGET(&window->gtk_window), ngettext
+ /* Translators: %d is the number of transactions. This is a
+ ngettext(3) message. */
+ ("There are no Scheduled Transactions to be entered at this time. "
+ "(%d transaction automatically created)",
+ "There are no Scheduled Transactions to be entered at this time. "
+ "(%d transactions automatically created)",
+ summary.num_auto_create_no_notify_instances),
+ summary.num_auto_create_no_notify_instances);
+ }
+ }
+ g_object_unref(G_OBJECT(sx_instances));
}
static void
Copied: gnucash/trunk/src/gnome/gnc-plugin-page-sx-list.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.c)
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.c 2007-01-15 01:57:07 UTC (rev 15384)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-sx-list.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -0,0 +1,628 @@
+/*
+ * gnc-plugin-page-sx-list.c
+ *
+ * Copyright (C) 2006 Josh Sled <jsled at asynchronous.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/* todo:
+ * - ui, actions, menus
+ * - icon
+ */
+
+/** @addtogroup ContentPlugins
+ @{ */
+/** @addtogroup GncPluginPageSxList A SX List Plugin Page
+ @{ */
+/** @brief Functions providing the SX List as a plugin page.
+ @author Josh Sled <jsled at asynchronous.org>
+*/
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glade/glade-xml.h>
+#ifndef HAVE_GLIB26
+#include "gkeyfile.h"
+#endif
+#include "gnc-exp-parser.h"
+#include "gnc-engine.h"
+#include "Transaction.h"
+#include "Split.h"
+#include "gnc-commodity.h"
+#include "gnc-event.h"
+#include "gnc-dense-cal.h"
+#include "gnc-glib-utils.h"
+#include "gnc-icons.h"
+#include "gnc-plugin-page-sx-list.h"
+#include "gnc-sx-instance-model.h"
+#include "gnc-sx-instance-dense-cal-adapter.h"
+#include "gnc-sx-list-tree-model-adapter.h"
+#include "gnc-ui-util.h"
+#include "gnc-main-window.h"
+#include "dialog-utils.h"
+#include "gnc-component-manager.h"
+#include "SX-book.h"
+#include "gnc-book.h"
+#include "dialog-sx-editor.h"
+
+/* This static indicates the debugging module that this .o belongs to. */
+static QofLogModule log_module = GNC_MOD_GUI;
+
+#define PLUGIN_PAGE_SX_LIST_CM_CLASS "plugin-page-sx-list"
+#define GCONF_SECTION "window/pages/sx_list"
+
+typedef struct GncPluginPageSxListPrivate
+{
+ gboolean disposed;
+
+ GtkWidget* widget;
+ gint gnc_component_id;
+
+ GladeXML* gxml;
+ GncSxInstanceDenseCalAdapter *dense_cal_model;
+ GncDenseCal* gdcal;
+
+ GncSxInstanceModel* instances;
+ GncSxListTreeModelAdapter* tree_model;
+ GtkTreeView* tree_view;
+} GncPluginPageSxListPrivate;
+
+#define GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_PAGE_SX_LIST, GncPluginPageSxListPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+/************************************************************
+ * Prototypes *
+ ************************************************************/
+/* Plugin Actions */
+static void gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass);
+static void gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page);
+static void gnc_plugin_page_sx_list_dispose(GObject *object);
+static void gnc_plugin_page_sx_list_finalize(GObject *object);
+
+static GtkWidget *gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page);
+static void gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page);
+static void gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
+static GncPluginPage *gnc_plugin_page_sx_list_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
+
+static void gppsl_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data);
+
+/* Callbacks */
+static void gnc_plugin_page_sx_list_cmd_new(GtkAction *action, GncPluginPageSxList *page);
+static void gnc_plugin_page_sx_list_cmd_edit(GtkAction *action, GncPluginPageSxList *page);
+static void gnc_plugin_page_sx_list_cmd_delete(GtkAction *action, GncPluginPageSxList *page);
+
+/* Command callbacks */
+
+static GtkActionEntry gnc_plugin_page_sx_list_actions [] = {
+ { "SxListAction", NULL, N_("Scheduled"), NULL, NULL, NULL },
+ { "SxListNewAction", GNC_STOCK_NEW_ACCOUNT, N_("New"), NULL,
+ N_("Create a new scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_new) },
+ { "SxListEditAction", GNC_STOCK_EDIT_ACCOUNT, N_("Edit"), NULL,
+ N_("Edit the selected scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_edit) },
+ { "SxListDeleteAction", GNC_STOCK_DELETE_ACCOUNT, N_("Delete"), NULL,
+ N_("Delete the selected scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_delete) },
+};
+/** The number of actions provided by this plugin. */
+static guint gnc_plugin_page_sx_list_n_actions = G_N_ELEMENTS (gnc_plugin_page_sx_list_actions);
+
+GType
+gnc_plugin_page_sx_list_get_type (void)
+{
+ static GType gnc_plugin_page_sx_list_type = 0;
+
+ if (gnc_plugin_page_sx_list_type == 0) {
+ static const GTypeInfo our_info = {
+ sizeof (GncPluginPageSxListClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gnc_plugin_page_sx_list_class_init,
+ NULL,
+ NULL,
+ sizeof (GncPluginPageSxList),
+ 0,
+ (GInstanceInitFunc) gnc_plugin_page_sx_list_init
+ };
+
+ gnc_plugin_page_sx_list_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE,
+ GNC_PLUGIN_PAGE_SX_LIST_NAME,
+ &our_info, 0);
+ }
+
+ return gnc_plugin_page_sx_list_type;
+}
+
+GncPluginPage *
+gnc_plugin_page_sx_list_new (void)
+{
+ GncPluginPageSxList *plugin_page;
+ plugin_page = g_object_new(GNC_TYPE_PLUGIN_PAGE_SX_LIST, NULL);
+ return GNC_PLUGIN_PAGE(plugin_page);
+}
+
+static void
+gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->dispose = gnc_plugin_page_sx_list_dispose;
+ object_class->finalize = gnc_plugin_page_sx_list_finalize;
+
+ gnc_plugin_class->tab_icon = GNC_STOCK_ACCOUNT;
+ gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_SX_LIST_NAME;
+ gnc_plugin_class->create_widget = gnc_plugin_page_sx_list_create_widget;
+ gnc_plugin_class->destroy_widget = gnc_plugin_page_sx_list_destroy_widget;
+ gnc_plugin_class->save_page = gnc_plugin_page_sx_list_save_page;
+ gnc_plugin_class->recreate_page = gnc_plugin_page_sx_list_recreate_page;
+
+ g_type_class_add_private(klass, sizeof(GncPluginPageSxListPrivate));
+}
+
+static void
+gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page)
+{
+ GtkActionGroup *action_group;
+ GncPluginPageSxListPrivate *priv;
+ GncPluginPage *parent;
+
+ ENTER("page %p", plugin_page);
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
+
+ /* Init parent declared variables */
+ parent = GNC_PLUGIN_PAGE(plugin_page);
+ g_object_set(G_OBJECT(plugin_page),
+ "page-name", _("Scheduled Transactions"),
+ "page-uri", "default:",
+ "ui-description", "gnc-plugin-page-sx-list-ui.xml",
+ NULL);
+
+ /* change me when the system supports multiple books */
+ gnc_plugin_page_add_book(parent, gnc_get_current_book());
+
+ /* Create menu and toolbar information */
+ action_group =
+ gnc_plugin_page_create_action_group(parent,
+ "GncPluginPageSxListActions");
+ gtk_action_group_add_actions(action_group,
+ gnc_plugin_page_sx_list_actions,
+ gnc_plugin_page_sx_list_n_actions,
+ plugin_page);
+ /* gnc_plugin_init_short_names (action_group, toolbar_labels); */
+
+ LEAVE("page %p, priv %p, action group %p",
+ plugin_page, priv, action_group);
+}
+
+static void
+gnc_plugin_page_sx_list_dispose(GObject *object)
+{
+ GncPluginPageSxList *page;
+ GncPluginPageSxListPrivate *priv;
+
+ ENTER("object %p", object);
+
+ page = GNC_PLUGIN_PAGE_SX_LIST (object);
+ g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST (page));
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ g_return_if_fail(priv != NULL);
+
+ g_return_if_fail(!priv->disposed);
+ priv->disposed = TRUE;
+
+ g_object_unref(G_OBJECT(priv->dense_cal_model));
+ priv->dense_cal_model = NULL;
+ gtk_widget_unref(GTK_WIDGET(priv->gdcal));
+ priv->gdcal = NULL;
+ g_object_unref(G_OBJECT(priv->instances));
+ priv->instances = NULL;
+ g_object_unref(G_OBJECT(priv->tree_model));
+ priv->tree_model = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose(object);
+ LEAVE(" ");
+}
+
+static void
+gnc_plugin_page_sx_list_finalize (GObject *object)
+{
+ GncPluginPageSxList *page;
+ GncPluginPageSxListPrivate *priv;
+
+ ENTER("object %p", object);
+
+ page = GNC_PLUGIN_PAGE_SX_LIST (object);
+ g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST (page));
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ g_return_if_fail(priv != NULL);
+
+ // by virtue of being a g_type_instance_..._private, does the private
+ // data get freed somewhere else?
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+ LEAVE(" ");
+}
+
+/* Virtual Functions */
+static void
+gnc_plugin_page_sx_list_refresh_cb (GHashTable *changes, gpointer user_data)
+{
+ GncPluginPageSxList *page = user_data;
+ GncPluginPageSxListPrivate *priv;
+
+ g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST(page));
+
+ /* We're only looking for forced updates here. */
+ if (changes)
+ return;
+
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ gtk_widget_queue_draw(priv->widget);
+}
+
+static void
+gnc_plugin_page_sx_list_close_cb (gpointer user_data)
+{
+ GncPluginPage *plugin_page;
+ GncPluginPageSxList *page;
+
+ plugin_page = GNC_PLUGIN_PAGE(user_data);
+ page = GNC_PLUGIN_PAGE_SX_LIST (plugin_page);
+ gnc_main_window_close_page(plugin_page);
+}
+
+static void
+gppsl_selection_changed_cb(GtkTreeSelection *selection, gpointer user_data)
+{
+ GncPluginPage *page;
+ GtkAction *edit_action, *delete_action;
+ gboolean selection_state = TRUE;
+
+ page = GNC_PLUGIN_PAGE(user_data);
+ edit_action = gnc_plugin_page_get_action(page, "SxListEditAction");
+ delete_action = gnc_plugin_page_get_action(page, "SxListDeleteAction");
+ selection_state
+ = gtk_tree_selection_count_selected_rows(selection) == 0
+ ? FALSE
+ : TRUE;
+ gtk_action_set_sensitive(edit_action, selection_state);
+ gtk_action_set_sensitive(delete_action, selection_state);
+}
+
+static GtkWidget *
+gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page)
+{
+ GncPluginPageSxList *page;
+ GncPluginPageSxListPrivate *priv;
+
+ ENTER("page %p", plugin_page);
+ page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ if (priv->widget != NULL) {
+ LEAVE("widget = %p", priv->widget);
+ return priv->widget;
+ }
+
+ priv->gxml = gnc_glade_xml_new("sched-xact.glade", "sx-list-vbox");
+ priv->widget = glade_xml_get_widget(priv->gxml, "sx-list-vbox");
+
+ {
+ //gint half_way;
+ // half_way = plugin_page->notebook_page->allocation.height * 0.5;
+ // fixme; get a real value:
+ gtk_paned_set_position(GTK_PANED(priv->widget), 160);
+ }
+
+ {
+ GDate end;
+ g_date_clear(&end, 1);
+ g_date_set_time_t(&end, time(NULL));
+ g_date_add_years(&end, 1);
+ priv->instances = GNC_SX_INSTANCE_MODEL(gnc_sx_get_instances(&end));
+ }
+
+ {
+ GtkAction *edit_action, *delete_action;
+ edit_action = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(page), "SxListEditAction");
+ delete_action = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(page), "SxListDeleteAction");
+ gtk_action_set_sensitive(edit_action, FALSE);
+ gtk_action_set_sensitive(delete_action, FALSE);
+ }
+
+ {
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ priv->tree_model = gnc_sx_list_tree_model_adapter_new(priv->instances);
+ priv->tree_view = GTK_TREE_VIEW(glade_xml_get_widget(priv->gxml, "sx_list"));
+ gtk_tree_view_set_model(priv->tree_view, GTK_TREE_MODEL(priv->tree_model));
+ gtk_tree_view_set_headers_clickable(priv->tree_view, TRUE);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", SXLTMA_COL_NAME, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, SXLTMA_COL_NAME);
+ gtk_tree_view_append_column(priv->tree_view, column);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Frequency", renderer, "text", SXLTMA_COL_FREQUENCY, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, SXLTMA_COL_FREQUENCY);
+ gtk_tree_view_append_column(priv->tree_view, column);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Last Occur", renderer, "text", SXLTMA_COL_LAST_OCCUR, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, SXLTMA_COL_LAST_OCCUR);
+ gtk_tree_view_append_column(priv->tree_view, column);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Next Occur", renderer, "text", SXLTMA_COL_NEXT_OCCUR, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, SXLTMA_COL_NEXT_OCCUR);
+ gtk_tree_view_append_column(priv->tree_view, column);
+
+ selection = gtk_tree_view_get_selection(priv->tree_view);
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+ g_signal_connect(G_OBJECT(selection), "changed", (GCallback)gppsl_selection_changed_cb, (gpointer)page);
+
+ g_signal_connect(G_OBJECT(priv->tree_view), "row-activated", (GCallback)gppsl_row_activated_cb, (gpointer)page);
+ }
+
+ {
+ GtkWidget *w;
+
+ priv->dense_cal_model = gnc_sx_instance_dense_cal_adapter_new(GNC_SX_INSTANCE_MODEL(priv->instances));
+ priv->gdcal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(priv->dense_cal_model)));
+ // gobject-2.10: g_object_ref_sink(G_OBJECT(priv->gdcal));
+ g_object_ref(G_OBJECT(priv->gdcal));
+ gtk_object_sink(GTK_OBJECT(priv->gdcal));
+ gnc_dense_cal_set_months_per_col(priv->gdcal, 4);
+ gnc_dense_cal_set_num_months(priv->gdcal, 12);
+
+ w = glade_xml_get_widget(priv->gxml, "upcoming_cal_hbox");
+ gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(priv->gdcal));
+ gtk_widget_show_all(w);
+ }
+
+ priv->gnc_component_id = gnc_register_gui_component("plugin-page-sx-list",
+ gnc_plugin_page_sx_list_refresh_cb,
+ gnc_plugin_page_sx_list_close_cb,
+ page);
+
+ /* @@fixme */
+ /* gnc_restore_window_size(SX_LIST_GCONF_SECTION, GTK_WINDOW(priv->widget)); */
+
+ return priv->widget;
+}
+
+static void
+gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page)
+{
+ GncPluginPageSxList *page;
+ GncPluginPageSxListPrivate *priv;
+
+ ENTER("page %p", plugin_page);
+ page = GNC_PLUGIN_PAGE_SX_LIST (plugin_page);
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+
+ if (priv->widget) {
+ g_object_unref(G_OBJECT(priv->widget));
+ priv->widget = NULL;
+ }
+
+ if (priv->gnc_component_id) {
+ gnc_unregister_gui_component(priv->gnc_component_id);
+ priv->gnc_component_id = 0;
+ }
+
+ LEAVE("widget destroyed");
+}
+
+/**
+ * Save enough information about this page that it can be recreated next time
+ * the user starts gnucash.
+ * @param page The page to save.
+ * @param key_file A pointer to the GKeyFile data structure where the
+ * page information should be written.
+ * @param group_name The group name to use when saving data.
+ **/
+static void
+gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page,
+ GKeyFile *key_file,
+ const gchar *group_name)
+{
+ GncPluginPageSxList *page;
+ GncPluginPageSxListPrivate *priv;
+
+ g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
+ g_return_if_fail(key_file != NULL);
+ g_return_if_fail(group_name != NULL);
+
+ ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
+ group_name);
+
+ page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+
+#if 0
+ gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
+ &priv->fd, key_file, group_name);
+#endif /* 0 */
+ LEAVE(" ");
+}
+
+/**
+ * Create a new sx list page based on the information saved during a previous
+ * instantiation of gnucash.
+ * @param window The window where this page should be installed.
+ * @param key_file A pointer to the GKeyFile data structure where the
+ * page information should be read.
+ * @param group_name The group name to use when restoring data.
+ **/
+static GncPluginPage *
+gnc_plugin_page_sx_list_recreate_page (GtkWidget *window,
+ GKeyFile *key_file,
+ const gchar *group_name)
+{
+ GncPluginPageSxList *page;
+ GncPluginPageSxListPrivate *priv;
+
+ g_return_val_if_fail(key_file, NULL);
+ g_return_val_if_fail(group_name, NULL);
+ ENTER("key_file %p, group_name %s", key_file, group_name);
+
+ /* Create the new page. */
+ page = GNC_PLUGIN_PAGE_SX_LIST(gnc_plugin_page_sx_list_new());
+ priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+
+ /* Install it now so we can them manipulate the created widget */
+ gnc_main_window_open_page(GNC_MAIN_WINDOW(window), GNC_PLUGIN_PAGE(page));
+
+#if 0
+ gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
+ &priv->fd, key_file, group_name);
+#endif /* 0 */
+ LEAVE(" ");
+ return GNC_PLUGIN_PAGE(page);
+}
+
+
+/* Callbacks */
+
+static SchedXaction*
+_sx_for_path(gpointer data, gpointer user_data)
+{
+ GtkTreeIter iter;
+ GncSxListTreeModelAdapter *model = GNC_SX_LIST_TREE_MODEL_ADAPTER(user_data);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, (GtkTreePath*)data);
+ return gnc_sx_list_tree_model_adapter_get_sx_instances(model, &iter)->sx;
+}
+
+static void
+gnc_plugin_page_sx_list_cmd_new(GtkAction *action, GncPluginPageSxList *page)
+{
+ FreqSpec *fs;
+ SchedXaction *new_sx;
+ gboolean new_sx_flag = TRUE;
+
+ new_sx = xaccSchedXactionMalloc(gnc_get_current_book());
+ /* Give decent initial FreqSpec for SX */
+ fs = xaccSchedXactionGetFreqSpec(new_sx);
+ {
+ GDate *now;
+ now = g_date_new();
+ g_date_set_time_t(now, time(NULL));
+ xaccFreqSpecSetMonthly(fs, now, 1);
+ xaccFreqSpecSetUIType(fs, UIFREQ_MONTHLY);
+ g_date_free(now);
+ }
+ gnc_ui_scheduled_xaction_editor_dialog_create(new_sx, new_sx_flag);
+}
+
+static void
+_edit_sx(gpointer data, gpointer user_data)
+{
+ gnc_ui_scheduled_xaction_editor_dialog_create((SchedXaction*)data, FALSE);
+}
+
+static void
+gnc_plugin_page_sx_list_cmd_edit(GtkAction *action, GncPluginPageSxList *page)
+{
+ GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ GtkTreeSelection *selection;
+ GList *selected_paths, *to_edit;
+ GtkTreeModel *model;
+
+ selection = gtk_tree_view_get_selection(priv->tree_view);
+ selected_paths = gtk_tree_selection_get_selected_rows(selection, &model);
+ if (g_list_length(selected_paths) == 0)
+ {
+ PERR("no selection edit.");
+ return;
+ }
+
+ to_edit = gnc_g_list_map(selected_paths, (GncGMapFunc)_sx_for_path, model);
+ g_list_foreach(to_edit, (GFunc)_edit_sx, NULL);
+ g_list_free(to_edit);
+ g_list_foreach(selected_paths, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(selected_paths);
+}
+
+static void
+gppsl_row_activated_cb(GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer user_data)
+{
+ GncPluginPageSxList *page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
+ GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ SchedXaction *sx = _sx_for_path(path, priv->tree_model);
+ gnc_ui_scheduled_xaction_editor_dialog_create(sx, FALSE);
+}
+
+
+static void
+_destroy_sx(gpointer data, gpointer user_data)
+{
+ SchedXactions *sxes;
+ SchedXaction *sx = (SchedXaction*)data;
+ GNCBook *book;
+ book = gnc_get_current_book();
+ sxes = gnc_book_get_schedxactions(book);
+ gnc_sxes_del_sx(sxes, sx);
+ xaccSchedXactionFree(sx);
+}
+
+static void
+gnc_plugin_page_sx_list_cmd_delete(GtkAction *action, GncPluginPageSxList *page)
+{
+ GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
+ GtkTreeSelection *selection;
+ GList *selected_paths, *to_delete = NULL;
+ GtkTreeModel *model;
+
+ /* @@fixme -- add (suppressible?) confirmation dialog */
+
+ selection = gtk_tree_view_get_selection(priv->tree_view);
+ selected_paths = gtk_tree_selection_get_selected_rows(selection, &model);
+ if (g_list_length(selected_paths) == 0)
+ {
+ PERR("no selection for delete.");
+ return;
+ }
+
+ to_delete = gnc_g_list_map(selected_paths, (GncGMapFunc)_sx_for_path, model);
+ {
+ GList *list;
+ for (list = to_delete; list != NULL; list = list->next)
+ {
+ DEBUG("to-delete [%s]\n", xaccSchedXactionGetName((SchedXaction*)list->data));
+ }
+ }
+ g_list_foreach(to_delete, (GFunc)_destroy_sx, NULL);
+ g_list_free(to_delete);
+ g_list_foreach(selected_paths, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(selected_paths);
+}
+
+/** @} */
+/** @} */
Copied: gnucash/trunk/src/gnome/gnc-plugin-page-sx-list.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.h)
Modified: gnucash/trunk/src/gnome/gnc-split-reg.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-split-reg.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/gnc-split-reg.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -5,7 +5,7 @@
* Copyright (C) 1998 Rob Browning <rlb at cs.utexas.edu> *
* Copyright (C) 1999-2000 Dave Peticolas <dave at krondo.com> *
* Copyright (C) 2001 Gnumatic, Inc. *
- * Copyright (C) 2002 Joshua Sled <jsled at asynchronous.org> *
+ * Copyright (C) 2002,2006 Joshua Sled <jsled at asynchronous.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -37,7 +37,7 @@
#include "QueryNew.h"
#include "SX-book.h"
#include "dialog-account.h"
-#include "dialog-scheduledxaction.h"
+#include "dialog-sx-editor.h"
#include "dialog-sx-from-trans.h"
#include "gnc-component-manager.h"
#include "gnc-date-edit.h"
@@ -1227,7 +1227,7 @@
GList *sxElts;
/* Get the correct SX */
- for ( sxElts = gnc_book_get_schedxactions( gnc_get_current_book() );
+ for ( sxElts = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
(!theSX) && sxElts;
sxElts = sxElts->next ) {
SchedXaction *sx = (SchedXaction*)sxElts->data;
@@ -1237,8 +1237,7 @@
}
if ( theSX ) {
- SchedXactionDialog *sxd = gnc_ui_scheduled_xaction_dialog_create();
- gnc_ui_scheduled_xaction_editor_dialog_create( sxd, theSX, FALSE );
+ gnc_ui_scheduled_xaction_editor_dialog_create(theSX, FALSE);
return;
}
}
Copied: gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/gnc-sx-list-tree-model-adapter.c)
Copied: gnucash/trunk/src/gnome/gnc-sx-list-tree-model-adapter.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/gnc-sx-list-tree-model-adapter.h)
Modified: gnucash/trunk/src/gnome/top-level.c
===================================================================
--- gnucash/trunk/src/gnome/top-level.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/top-level.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -33,7 +33,7 @@
#include "dialog-account.h"
#include "dialog-commodity.h"
#include "dialog-options.h"
-#include "dialog-scheduledxaction.h"
+#include "dialog-sx-editor.h"
#include "dialog-transfer.h"
#include "dialog-totd.h"
#include "druid-hierarchy.h"
Modified: gnucash/trunk/src/gnome/ui/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome/ui/Makefile.am 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome/ui/Makefile.am 2007-01-19 23:45:45 UTC (rev 15399)
@@ -8,6 +8,7 @@
gnc-plugin-file-history-ui.xml \
gnc-plugin-register-ui.xml \
gnc-plugin-page-register-ui.xml \
+ gnc-plugin-page-sx-list-ui.xml \
gnc-plugin-page-sxregister-ui.xml \
gnc-sxed-to-create-window-ui.xml \
gnc-reconcile-window-ui.xml \
Copied: gnucash/trunk/src/gnome/ui/gnc-plugin-page-sx-list-ui.xml (from rev 15384, gnucash/branches/sx-cleanup/src/gnome/ui/gnc-plugin-page-sx-list-ui.xml)
Modified: gnucash/trunk/src/gnome-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome-utils/Makefile.am 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome-utils/Makefile.am 2007-01-19 23:45:45 UTC (rev 15399)
@@ -49,6 +49,8 @@
gnc-date-edit.c \
gnc-date-format.c \
gnc-dense-cal.c \
+ gnc-dense-cal-model.c \
+ gnc-dense-cal-store.c \
gnc-druid-gnome.c \
gnc-druid-provider-edge-gnome.c \
gnc-druid-provider-file-gnome.c \
@@ -74,6 +76,7 @@
gnc-period-select.c \
gnc-query-list.c \
gnc-splash.c \
+ gnc-sx-instance-dense-cal-adapter.c \
gnc-tree-model.c \
gnc-tree-model-account-types.c \
gnc-tree-model-account.c \
@@ -117,6 +120,8 @@
gnc-date-edit.h \
gnc-date-format.h \
gnc-dense-cal.h \
+ gnc-dense-cal-model.h \
+ gnc-dense-cal-store.h \
gnc-druid-gnome-ui.h \
gnc-embedded-window.h \
gnc-file.h \
@@ -139,6 +144,7 @@
gnc-period-select.h \
gnc-query-list.h \
gnc-splash.h \
+ gnc-sx-instance-dense-cal-adapter.h \
gnc-tree-model.h \
gnc-tree-model-account-types.h \
gnc-tree-model-account.h \
Copied: gnucash/trunk/src/gnome-utils/gnc-dense-cal-model.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/gnc-dense-cal-model.c)
Copied: gnucash/trunk/src/gnome-utils/gnc-dense-cal-model.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/gnc-dense-cal-model.h)
Copied: gnucash/trunk/src/gnome-utils/gnc-dense-cal-store.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/gnc-dense-cal-store.c)
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome-utils/gnc-dense-cal-store.c 2007-01-15 01:57:07 UTC (rev 15384)
+++ gnucash/trunk/src/gnome-utils/gnc-dense-cal-store.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -0,0 +1,290 @@
+/*
+ * gnc-dense-cal-store.h
+ *
+ * Copyright (C) 2006 Joshua Sled <jsled at asynchronous.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+#include "config.h"
+#include <glib.h>
+#include <glib-object.h>
+#include "gnc-dense-cal.h"
+#include "gnc-dense-cal-model.h"
+#include "gnc-dense-cal-store.h"
+
+struct _GncDenseCalStore
+{
+ GObject parent;
+
+ GDate start_date;
+ gdcs_end_type end_type;
+ GDate end_date;
+ gint n_occurrences;
+ gchar *name;
+ gchar *info;
+ int num_marks;
+ int num_real_marks;
+ GDate **cal_marks;
+};
+
+struct _GncDenseCalStoreClass
+{
+ GObjectClass parent_class;
+};
+
+static GObjectClass *parent_class = NULL;
+
+static void gnc_dense_cal_store_class_init(GncDenseCalStoreClass *klass);
+
+static void gnc_dense_cal_store_finalize(GObject *obj);
+
+static GList* gdcs_get_contained(GncDenseCalModel *model);
+static gchar* gdcs_get_name(GncDenseCalModel *model, guint tag);
+static gchar* gdcs_get_info(GncDenseCalModel *model, guint tag);
+static gint gdcs_get_instance_count(GncDenseCalModel *model, guint tag);
+static void gdcs_get_instance(GncDenseCalModel *model, guint tag, gint instance_index, GDate *date);
+
+static void
+gnc_dense_cal_store_class_init(GncDenseCalStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->finalize = gnc_dense_cal_store_finalize;
+}
+
+static void
+gnc_dense_cal_store_iface_init(gpointer g_iface, gpointer iface_data)
+{
+ GncDenseCalModelIface *iface = (GncDenseCalModelIface*)g_iface;
+ iface->get_contained = gdcs_get_contained;
+ iface->get_name = gdcs_get_name;
+ iface->get_info = gdcs_get_info;
+ iface->get_instance_count = gdcs_get_instance_count;
+ iface->get_instance = gdcs_get_instance;
+}
+
+GType
+gnc_dense_cal_store_get_type(void)
+{
+ static GType type = 0;
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (GncDenseCalStoreClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc)gnc_dense_cal_store_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof(GncDenseCalStore),
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ static const GInterfaceInfo iDenseCalModelInfo = {
+ (GInterfaceInitFunc)gnc_dense_cal_store_iface_init,
+ NULL, /* interface finalize */
+ NULL, /* interface data */
+ };
+ type = g_type_register_static(G_TYPE_OBJECT, "GncDenseCalStore", &info, 0);
+ g_type_add_interface_static(type,
+ GNC_TYPE_DENSE_CAL_MODEL,
+ &iDenseCalModelInfo);
+ }
+ return type;
+}
+
+GncDenseCalStore*
+gnc_dense_cal_store_new(int num_marks)
+{
+ GncDenseCalStore *model = g_object_new(GNC_TYPE_DENSE_CAL_STORE, NULL);
+ model->num_marks = num_marks;
+ model->cal_marks = g_new0(GDate*, num_marks);
+ {
+ int i = 0;
+ for (i = 0; i < model->num_marks; i++)
+ {
+ model->cal_marks[i] = g_date_new();
+ }
+ }
+ model->num_real_marks = 0;
+ g_date_clear(&model->start_date, 1);
+ g_date_set_time_t(&model->start_date, time(NULL));
+ model->end_type = NEVER_END;
+ g_date_clear(&model->end_date, 1);
+ g_date_set_time_t(&model->end_date, time(NULL));
+ model->n_occurrences = 0;
+ return model;
+}
+
+void
+gnc_dense_cal_store_clear(GncDenseCalStore *model)
+{
+ model->num_real_marks = 0;
+ g_signal_emit_by_name(model, "update", GUINT_TO_POINTER(1));
+}
+
+void
+gnc_dense_cal_store_update_name(GncDenseCalStore *model, gchar *name)
+{
+ if (model->name != NULL)
+ {
+ g_free(model->name);
+ }
+ model->name = g_strdup(name);
+ g_signal_emit_by_name(model, "update", GUINT_TO_POINTER(1));
+}
+
+void
+gnc_dense_cal_store_update_info(GncDenseCalStore *model, gchar *info)
+{
+ if (model->info != NULL)
+ {
+ g_free(model->info);
+ }
+ model->info = g_strdup(info);
+ g_signal_emit_by_name(model, "update", GUINT_TO_POINTER(1));
+}
+
+static void
+gdcs_generic_update(GncDenseCalStore *trans, GDate *start, FreqSpec *fs)
+{
+ int i;
+ GDate date;
+
+ date = *start;
+ /* go one day before what's in the box so we can get the correct start
+ * date. */
+ g_date_subtract_days(&date, 1);
+ xaccFreqSpecGetNextInstance(fs, &date, &date);
+
+ i = 0;
+ while ((i < trans->num_marks)
+ && g_date_valid(&date)
+ /* Do checking against end restriction. */
+ && ((trans->end_type == NEVER_END)
+ || (trans->end_type == END_ON_DATE
+ && g_date_compare(&date, &trans->end_date) <= 0)
+ || (trans->end_type == END_AFTER_N_OCCS
+ && i < trans->n_occurrences)))
+ {
+ *trans->cal_marks[i++] = date;
+ xaccFreqSpecGetNextInstance(fs, &date, &date);
+ }
+ trans->num_real_marks = (i-1);
+ g_signal_emit_by_name(trans, "update", GUINT_TO_POINTER(1));
+}
+
+void
+gnc_dense_cal_store_update_no_end(GncDenseCalStore *model, GDate *start, FreqSpec *fs)
+{
+ model->end_type = NEVER_END;
+ gdcs_generic_update(model, start, fs);
+}
+
+void
+gnc_dense_cal_store_update_count_end(GncDenseCalStore *model, GDate *start, FreqSpec *fs, int num_occur)
+{
+ model->end_type = END_AFTER_N_OCCS;
+ model->n_occurrences = num_occur;
+ gdcs_generic_update(model, start, fs);
+}
+
+void
+gnc_dense_cal_store_update_date_end(GncDenseCalStore *model, GDate *start, FreqSpec *fs, GDate *end_date)
+{
+ model->end_type = END_ON_DATE;
+ model->end_date = *end_date;
+ gdcs_generic_update(model, start, fs);
+}
+
+static GList*
+gdcs_get_contained(GncDenseCalModel *model)
+{
+ GList *rtn = NULL;
+ rtn = g_list_append(rtn, GUINT_TO_POINTER(1));
+ return rtn;
+}
+
+static gchar*
+gdcs_get_name(GncDenseCalModel *model, guint tag)
+{
+ GncDenseCalStore *mdl = GNC_DENSE_CAL_STORE(model);
+ // assert(tag == 1)
+ return mdl->name;
+}
+
+static gchar*
+gdcs_get_info(GncDenseCalModel *model, guint tag)
+{
+ GncDenseCalStore *mdl = GNC_DENSE_CAL_STORE(model);
+ // assert(tag == 1)
+ return mdl->info;
+}
+
+static gint
+gdcs_get_instance_count(GncDenseCalModel *model, guint tag)
+{
+ GncDenseCalStore *mdl = GNC_DENSE_CAL_STORE(model);
+ // assert(tag == 1)
+ return mdl->num_real_marks;
+}
+
+static void
+gdcs_get_instance(GncDenseCalModel *model, guint tag, gint instance_index, GDate *date)
+{
+ GncDenseCalStore *mdl = GNC_DENSE_CAL_STORE(model);
+ // assert(tag == 1)
+ // assert 0 < instance_index < model->num_marks;
+ *date = *mdl->cal_marks[instance_index];
+}
+
+static void
+gnc_dense_cal_store_finalize(GObject *obj)
+{
+ int i;
+ GncDenseCalStore *store;
+ g_return_if_fail(obj != NULL);
+
+ store = GNC_DENSE_CAL_STORE(obj);
+
+ if (store->name != NULL)
+ {
+ g_free(store->name);
+ store->name = NULL;
+ }
+
+ if (store->info != NULL)
+ {
+ g_free(store->info);
+ store->info = NULL;
+ }
+
+ for (i = 0; i < store->num_marks; i++)
+ {
+ g_free(store->cal_marks[i]);
+ store->cal_marks[i] = NULL;
+ }
+ if (store->cal_marks != NULL)
+ {
+ g_free(store->cal_marks);
+ store->cal_marks = NULL;
+ }
+
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
Copied: gnucash/trunk/src/gnome-utils/gnc-dense-cal-store.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/gnc-dense-cal-store.h)
Modified: gnucash/trunk/src/gnome-utils/gnc-dense-cal.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-dense-cal.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome-utils/gnc-dense-cal.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,6 +1,6 @@
/********************************************************************\
* gnc-dense-cal.c : a custom densely-dispalyed calendar widget *
- * Copyright (C) 2002 Joshua Sled <jsled at asynchronous.org> *
+ * Copyright (C) 2002,2006 Joshua Sled <jsled at asynchronous.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -22,28 +22,16 @@
#include "config.h"
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
#include "glib-compat.h"
-#include <math.h>
-
#include "gnc-dense-cal.h"
-
-/* For PERR, only... */
+#include "gnc-dense-cal-model.h"
#include "gnc-engine.h"
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <math.h>
/**
- * Todo:
- * . marking
- * . color-per-marker (configurable)
- * X all-or-nothing
- * \ handle errors properly
- * X mouse-over -> "hottip"
- * X rotated month labels
- * X weeksPerCol -> monthsPerCol
- **/
-
-/**
* Marking ...
*
* We want a facility to mark multiple days on the calendar. This facility
@@ -84,16 +72,6 @@
static const gchar* MARK_COLOR = "Yellow";
-static const gchar* MARKS_LOST_SIGNAL_NAME = "marks_lost";
-
-/* SIGNALS */
-enum gnc_dense_cal_signal_enum {
- MARKS_LOST_SIGNAL,
- LAST_SIGNAL
-};
-
-static guint gnc_dense_cal_signals[LAST_SIGNAL] = { 0 };
-
static QofLogModule log_module = GNC_MOD_SX;
static void gnc_dense_cal_class_init (GncDenseCalClass *class);
@@ -101,69 +79,72 @@
static void gnc_dense_cal_finalize (GObject *object);
static void gnc_dense_cal_dispose (GObject *object);
static void gnc_dense_cal_realize (GtkWidget *widget);
-static void gnc_dense_cal_draw_to_buffer( GncDenseCal *dcal );
-static gint gnc_dense_cal_expose( GtkWidget *widget,
- GdkEventExpose *event );
+static void gnc_dense_cal_draw_to_buffer(GncDenseCal *dcal);
+static gint gnc_dense_cal_expose(GtkWidget *widget,
+ GdkEventExpose *event);
-static void gdc_reconfig( GncDenseCal *dcal );
+static void gdc_reconfig(GncDenseCal *dcal);
-static void gdc_free_all_mark_data( GncDenseCal *dcal );
+static void gdc_free_all_mark_data(GncDenseCal *dcal);
-static void gnc_dense_cal_size_request( GtkWidget *widget,
+static void gnc_dense_cal_size_request(GtkWidget *widget,
GtkRequisition *requisition);
-static void gnc_dense_cal_size_allocate( GtkWidget *widget,
- GtkAllocation *allocation );
-static gint gnc_dense_cal_motion_notify( GtkWidget *widget,
- GdkEventMotion *event );
-static gint gnc_dense_cal_button_press( GtkWidget *widget,
- GdkEventButton *evt );
+static void gnc_dense_cal_size_allocate(GtkWidget *widget,
+ GtkAllocation *allocation);
+static gint gnc_dense_cal_motion_notify(GtkWidget *widget,
+ GdkEventMotion *event);
+static gint gnc_dense_cal_button_press(GtkWidget *widget,
+ GdkEventButton *evt);
-static inline int day_width_at( GncDenseCal *dcal, guint xScale );
-static inline int day_width( GncDenseCal *dcal );
-static inline int day_height_at( GncDenseCal *dcal, guint yScale );
-static inline int day_height( GncDenseCal *dcal );
-static inline int week_width_at( GncDenseCal *dcal, guint xScale );
-static inline int week_width( GncDenseCal *dcal );
-static inline int week_height_at( GncDenseCal *dcal, guint yScale );
-static inline int week_height( GncDenseCal *dcal );
-static inline int col_width_at( GncDenseCal *dcal, guint xScale );
-static inline int col_width( GncDenseCal *dcal );
+static inline int day_width_at(GncDenseCal *dcal, guint xScale);
+static inline int day_width(GncDenseCal *dcal);
+static inline int day_height_at(GncDenseCal *dcal, guint yScale);
+static inline int day_height(GncDenseCal *dcal);
+static inline int week_width_at(GncDenseCal *dcal, guint xScale);
+static inline int week_width(GncDenseCal *dcal);
+static inline int week_height_at(GncDenseCal *dcal, guint yScale);
+static inline int week_height(GncDenseCal *dcal);
+static inline int col_width_at(GncDenseCal *dcal, guint xScale);
+static inline int col_width(GncDenseCal *dcal);
-static inline int col_height( GncDenseCal *dcal );
-static inline int num_cols( GncDenseCal *dcal );
+static inline int col_height(GncDenseCal *dcal);
+static inline int num_cols(GncDenseCal *dcal);
/**
* Returns the total number of weeks to display in the calendar [irrespective
* of columns/weeks-per-col].
**/
-static inline int num_weeks( GncDenseCal *dcal );
+static inline int num_weeks(GncDenseCal *dcal);
/**
* Returns the number of weeks per column. Note that this is the number of
* weeks needed to display the longest column.
**/
-static int num_weeks_per_col( GncDenseCal *dcal );
+static int num_weeks_per_col(GncDenseCal *dcal);
/* hotspot calculation */
-static gint wheres_this( GncDenseCal *dcal, int x, int y );
+static gint wheres_this(GncDenseCal *dcal, int x, int y);
-static void recompute_x_y_scales( GncDenseCal *dcal );
-static void recompute_mark_storage( GncDenseCal *dcal );
-static void recompute_extents( GncDenseCal *dcal );
-static void populate_hover_window( GncDenseCal *dcal, gint doc );
+static void recompute_x_y_scales(GncDenseCal *dcal);
+static void recompute_mark_storage(GncDenseCal *dcal);
+static void recompute_extents(GncDenseCal *dcal);
+static void populate_hover_window(GncDenseCal *dcal, gint doc);
-static void month_coords( GncDenseCal *dcal, int monthOfCal, GList **outList );
-static void doc_coords( GncDenseCal *dcal, int dayOfCal,
- int *x1, int *y1, int *x2, int *y2 );
+static void month_coords(GncDenseCal *dcal, int monthOfCal, GList **outList);
+static void doc_coords(GncDenseCal *dcal, int dayOfCal,
+ int *x1, int *y1, int *x2, int *y2);
+static void gdc_mark_add(GncDenseCal *dcal, guint tag, gchar *name, gchar *info, guint size, GDate **dateArray);
+static void gdc_mark_remove(GncDenseCal *dcal, guint mark_to_remove);
+
+static void gdc_add_tag_markings(GncDenseCal *cal, guint tag);
+static void gdc_add_markings(GncDenseCal *cal);
+static void gdc_remove_markings(GncDenseCal *cal);
+
static GtkWidgetClass *parent_class = NULL;
-/*static const gchar* MONTH_NAMES[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };*/
#define MONTH_NAME_BUFSIZE 5
/* Takes the number of months since January, in the range 0 to
* 11. Returns the abbreviated month name according to the current
- * locale. (i18n'd version of the above static character array.) */
+ * locale.*/
static const gchar *month_name(int mon)
{
static gchar buf[MONTH_NAME_BUFSIZE];
@@ -177,10 +158,6 @@
return buf;
}
-/* FIXME: i18n
- static const gchar *dayLabels[7] = {
- "Su", "M", "Tu", "W", "Th", "F", "Sa"
- };*/
/* Takes the number of days since Sunday, in the range 0 to 6. Returns
* the abbreviated weekday name according to the current locale. */
static const gchar *day_label(int wday)
@@ -189,8 +166,8 @@
struct tm my_tm;
int i;
- memset( buf, 0, MONTH_NAME_BUFSIZE );
- memset( &my_tm, 0, sizeof( struct tm ) );
+ memset(buf, 0, MONTH_NAME_BUFSIZE);
+ memset(&my_tm, 0, sizeof(struct tm));
my_tm.tm_wday = wday;
i = strftime (buf, MONTH_NAME_BUFSIZE-1, "%a", &my_tm);
/* Wild hack to use only the first two letters */
@@ -198,1060 +175,1076 @@
return buf;
}
-
GType
-gnc_dense_cal_get_type ()
+gnc_dense_cal_get_type()
{
- static GType dense_cal_type = 0;
+ static GType dense_cal_type = 0;
- if (dense_cal_type == 0) {
- static const GTypeInfo dense_cal_info = {
- sizeof (GncDenseCalClass),
- NULL,
- NULL,
- (GClassInitFunc) gnc_dense_cal_class_init,
- NULL,
- NULL,
- sizeof (GncDenseCal),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gnc_dense_cal_init,
- NULL
- };
+ if (dense_cal_type == 0) {
+ static const GTypeInfo dense_cal_info = {
+ sizeof (GncDenseCalClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gnc_dense_cal_class_init,
+ NULL,
+ NULL,
+ sizeof (GncDenseCal),
+ 0,
+ (GInstanceInitFunc) gnc_dense_cal_init,
+ NULL
+ };
- dense_cal_type = g_type_register_static(GTK_TYPE_WIDGET,
- "GncDenseCal",
- &dense_cal_info, 0);
- }
+ dense_cal_type = g_type_register_static(GTK_TYPE_WIDGET,
+ "GncDenseCal",
+ &dense_cal_info, 0);
+ }
- return dense_cal_type;
+ return dense_cal_type;
}
static void
-gnc_dense_cal_class_init (GncDenseCalClass *klass)
+gnc_dense_cal_class_init(GncDenseCalClass *klass)
{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
- object_class = G_OBJECT_CLASS (klass);
- widget_class = GTK_WIDGET_CLASS (klass);
+ object_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
- parent_class = g_type_class_peek_parent (klass);
+ parent_class = g_type_class_peek_parent (klass);
- gnc_dense_cal_signals[MARKS_LOST_SIGNAL] =
- g_signal_new (MARKS_LOST_SIGNAL_NAME,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GncDenseCalClass, marks_lost_cb),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
+ object_class->finalize = gnc_dense_cal_finalize;
+ object_class->dispose = gnc_dense_cal_dispose;
- object_class->finalize = gnc_dense_cal_finalize;
- object_class->dispose = gnc_dense_cal_dispose;
-
- widget_class->realize = gnc_dense_cal_realize;
- widget_class->expose_event = gnc_dense_cal_expose;
- widget_class->size_request = gnc_dense_cal_size_request;
- widget_class->size_allocate = gnc_dense_cal_size_allocate;
- widget_class->motion_notify_event = gnc_dense_cal_motion_notify;
- widget_class->button_press_event = gnc_dense_cal_button_press;
+ widget_class->realize = gnc_dense_cal_realize;
+ widget_class->expose_event = gnc_dense_cal_expose;
+ widget_class->size_request = gnc_dense_cal_size_request;
+ widget_class->size_allocate = gnc_dense_cal_size_allocate;
+ widget_class->motion_notify_event = gnc_dense_cal_motion_notify;
+ widget_class->button_press_event = gnc_dense_cal_button_press;
}
static void
-gnc_dense_cal_init (GncDenseCal *dcal)
+gnc_dense_cal_init(GncDenseCal *dcal)
{
- gboolean colorAllocSuccess;
+ gboolean colorAllocSuccess;
- dcal->disposed = FALSE;
- dcal->initialized = FALSE;
- dcal->markData = NULL;
- dcal->numMarks = 0;
- dcal->marks = NULL;
- dcal->lastMarkTag = 0;
+ dcal->disposed = FALSE;
+ dcal->initialized = FALSE;
+ dcal->markData = NULL;
+ dcal->numMarks = 0;
+ dcal->marks = NULL;
+ dcal->lastMarkTag = 0;
- dcal->showPopup = FALSE;
+ dcal->showPopup = FALSE;
- dcal->transPopup = GTK_WINDOW( gtk_window_new( GTK_WINDOW_POPUP ) );
- {
- GtkWidget *vbox, *hbox;
- GtkWidget *l;
- GtkCList *cl;
- static gchar *CLIST_TITLES[2];
- CLIST_TITLES[0] = _("Name");
- CLIST_TITLES[1] = _("Frequency");
+ dcal->transPopup = GTK_WINDOW(gtk_window_new(GTK_WINDOW_POPUP));
+ {
+ GtkWidget *vbox, *hbox;
+ GtkWidget *l;
+ GtkListStore *tree_data;
+ GtkTreeView *tree_view;
- vbox = gtk_vbox_new( FALSE, 5 );
- hbox = gtk_hbox_new( FALSE, 5 );
+ vbox = gtk_vbox_new(FALSE, 5);
+ hbox = gtk_hbox_new(FALSE, 5);
- l = gtk_label_new( _("Date: ") );
- gtk_container_add( GTK_CONTAINER(hbox), l );
- l = gtk_label_new( "YY/MM/DD" );
- g_object_set_data( G_OBJECT(dcal->transPopup), "dateLabel", l );
- gtk_container_add( GTK_CONTAINER(hbox), l );
- gtk_container_add( GTK_CONTAINER(vbox), hbox );
+ l = gtk_label_new(_("Date: "));
+ gtk_container_add(GTK_CONTAINER(hbox), l);
+ l = gtk_label_new("YY/MM/DD");
+ g_object_set_data(G_OBJECT(dcal->transPopup), "dateLabel", l);
+ gtk_container_add(GTK_CONTAINER(hbox), l);
+ gtk_container_add(GTK_CONTAINER(vbox), hbox);
- gtk_container_add( GTK_CONTAINER(vbox), gtk_hseparator_new() );
+ gtk_container_add(GTK_CONTAINER(vbox), gtk_hseparator_new());
- cl = GTK_CLIST(gtk_clist_new_with_titles(2, (gchar**)CLIST_TITLES));
- gtk_clist_set_column_auto_resize( cl, 0, TRUE );
- gtk_clist_set_column_auto_resize( cl, 1, TRUE );
- g_object_set_data( G_OBJECT(dcal->transPopup), "clist", cl );
- gtk_container_add( GTK_CONTAINER(vbox), GTK_WIDGET(cl) );
+ tree_data = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
+ tree_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_data)));
+ gtk_tree_view_insert_column_with_attributes(tree_view, -1, _("Name"), gtk_cell_renderer_text_new(), "text", 0, NULL);
+ gtk_tree_view_insert_column_with_attributes(tree_view, -1, _("Frequency"), gtk_cell_renderer_text_new(), "text", 1, NULL);
+ g_object_set_data(G_OBJECT(dcal->transPopup), "model", tree_data);
+ gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(tree_view));
- gtk_container_add( GTK_CONTAINER(dcal->transPopup), vbox );
+ gtk_container_add(GTK_CONTAINER(dcal->transPopup), vbox);
- gtk_widget_realize( GTK_WIDGET(dcal->transPopup) );
- }
+ gtk_widget_realize(GTK_WIDGET(dcal->transPopup));
+ }
- gdk_color_parse( MONTH_THIS_COLOR, &dcal->weekColors[MONTH_THIS] );
- gdk_color_parse( MONTH_THAT_COLOR, &dcal->weekColors[MONTH_THAT] );
- if ( gdk_colormap_alloc_colors( gdk_colormap_get_system(),
- dcal->weekColors,
- MAX_COLORS, TRUE, TRUE,
- &colorAllocSuccess ) > 0 ) {
- /* FIXME : handle [more] properly */
- PERR( "Error allocating colors\n" );
- }
+ gdk_color_parse(MONTH_THIS_COLOR, &dcal->weekColors[MONTH_THIS]);
+ gdk_color_parse(MONTH_THAT_COLOR, &dcal->weekColors[MONTH_THAT]);
+ if (gdk_colormap_alloc_colors(gdk_colormap_get_system(),
+ dcal->weekColors,
+ MAX_COLORS, TRUE, TRUE,
+ &colorAllocSuccess) > 0)
+ {
+ /* FIXME : handle [more] properly */
+ PERR("Error allocating colors\n");
+ }
+
+ /* Deal with the various label sizes. */
+ {
+ gint i;
+ gint maxWidth, maxHeight, maxAscent, maxLBearing;
+ gint lbearing, rbearing, width, ascent, descent;
+ GtkStyle *style;
- /* Deal with the various label sizes. */
- {
- gint i;
- gint maxWidth, maxHeight, maxAscent, maxLBearing;
- gint lbearing, rbearing, width, ascent, descent;
- GtkStyle *style;
+ /* @FIXME: GNOME 2 port (rework the complete font code) */
+ style = gtk_widget_get_style(GTK_WIDGET(dcal));
- /* FIXME GNOME 2 port (rework the complete font code) */
- style = gtk_widget_get_style(GTK_WIDGET(dcal));
+ dcal->dayLabelFont = gtk_style_get_font(style);
+ gdk_font_ref(dcal->dayLabelFont);
+ g_assert(dcal->dayLabelFont);
- dcal->dayLabelFont = gtk_style_get_font(style);
- gdk_font_ref( dcal->dayLabelFont );
- g_assert( dcal->dayLabelFont );
+ dcal->monthLabelFont = gtk_style_get_font(style);
+ g_assert(dcal->monthLabelFont);
+ gdk_font_ref(dcal->monthLabelFont);
- dcal->monthLabelFont = gtk_style_get_font(style);
- g_assert(dcal->monthLabelFont);
- gdk_font_ref(dcal->monthLabelFont);
+ maxWidth = maxHeight = maxAscent = maxLBearing = 0;
+ for (i=0; i<12; i++)
+ {
+ gint w, h;
+ gdk_string_extents(dcal->monthLabelFont, month_name(i),
+ &lbearing, &rbearing, &width,
+ &ascent, &descent);
+ w = rbearing - lbearing + 1;
+ h = ascent + descent;
+ maxLBearing = MAX(maxLBearing, ABS(lbearing));
+ maxWidth = MAX(maxWidth, w);
+ maxHeight = MAX(maxHeight, h);
+ maxAscent = MAX(maxAscent, ascent);
+ }
+ dcal->label_width = maxHeight + 1;
+ dcal->label_height = maxWidth;
+ dcal->label_lbearing = maxLBearing;
+ dcal->label_ascent = maxAscent;
+ dcal->needInitMonthLabels = TRUE;
+ }
- maxWidth = maxHeight = maxAscent = maxLBearing = 0;
- for ( i=0; i<12; i++ ) {
- gint w, h;
- gdk_string_extents( dcal->monthLabelFont, month_name(i),
- &lbearing, &rbearing, &width,
- &ascent, &descent );
- w = rbearing - lbearing + 1;
- h = ascent + descent;
- maxLBearing = MAX( maxLBearing, ABS(lbearing) );
- maxWidth = MAX( maxWidth, w );
- maxHeight = MAX( maxHeight, h );
- maxAscent = MAX( maxAscent, ascent );
- }
- dcal->label_width = maxHeight + 1;
- dcal->label_height = maxWidth;
- dcal->label_lbearing = maxLBearing;
- dcal->label_ascent = maxAscent;
- dcal->needInitMonthLabels = TRUE;
- }
+ dcal->month = G_DATE_JANUARY;
+ dcal->year = 1970;
- dcal->month = G_DATE_JANUARY;
- dcal->year = 1970;
+ dcal->numMonths = 12;
+ dcal->monthsPerCol = 3;
+ dcal->leftPadding = 2;
+ dcal->topPadding = 2;
- dcal->numMonths = 12;
- dcal->monthsPerCol = 3;
- dcal->leftPadding = 2;
- dcal->topPadding = 2;
+ {
+ GDate *now = g_date_new();
+ g_date_set_time_t(now, time(NULL));
+ gnc_dense_cal_set_month(dcal, g_date_get_month(now));
+ gnc_dense_cal_set_year(dcal, g_date_get_year(now));
+ g_date_free(now);
+ }
- {
- GDate *tmpDate;
+ recompute_extents(dcal);
+ recompute_mark_storage(dcal);
- tmpDate = g_date_new();
- g_date_set_time_t( tmpDate, time(NULL) );
- gnc_dense_cal_set_month( dcal, g_date_get_month(tmpDate) );
- gnc_dense_cal_set_year( dcal, g_date_get_year(tmpDate) );
- g_date_free( tmpDate );
- }
-
- recompute_extents( dcal );
- recompute_mark_storage( dcal );
-
- /* Now that we're "sure" of our configuration, compute initial
- * scaling factors; will be increased when we're allocated enough
- * space to scale up. */
- dcal->min_x_scale = dcal->x_scale =
- MAX( gdk_string_width( dcal->monthLabelFont, "88" ),
- gdk_string_width( dcal->dayLabelFont, "88" ) + 2 );
- dcal->min_y_scale = dcal->y_scale =
- MAX( floor( (float)gdk_string_width( dcal->monthLabelFont,
- "XXX" )
- / 3.0 ),
- gdk_string_height( dcal->dayLabelFont, "88" ) + 2 );
- dcal->dayLabelHeight = gdk_string_height( dcal->monthLabelFont, "88" );
- dcal->initialized = TRUE;
+ /* Now that we're "sure" of our configuration, compute initial
+ * scaling factors; will be increased when we're allocated enough
+ * space to scale up. */
+ dcal->min_x_scale = dcal->x_scale =
+ MAX(gdk_string_width(dcal->monthLabelFont, "88"),
+ gdk_string_width(dcal->dayLabelFont, "88") + 2);
+ dcal->min_y_scale = dcal->y_scale =
+ MAX(floor((float)gdk_string_width(dcal->monthLabelFont,
+ "XXX")
+ / 3.0),
+ gdk_string_height(dcal->dayLabelFont, "88") + 2);
+ dcal->dayLabelHeight = gdk_string_height(dcal->monthLabelFont, "88");
+ dcal->initialized = TRUE;
}
GtkWidget*
gnc_dense_cal_new(void)
{
- GncDenseCal *dcal;
- dcal = g_object_new(GNC_TYPE_DENSE_CAL, NULL, NULL);
+ GncDenseCal *dcal;
+ dcal = g_object_new(GNC_TYPE_DENSE_CAL, NULL);
+ return GTK_WIDGET(dcal);
+}
- return GTK_WIDGET (dcal);
+GtkWidget*
+gnc_dense_cal_new_with_model(GncDenseCalModel *model)
+{
+ GncDenseCal *cal = GNC_DENSE_CAL(gnc_dense_cal_new());
+ gnc_dense_cal_set_model(cal, model);
+ return GTK_WIDGET(cal);
}
static void
-recompute_first_of_month_offset( GncDenseCal *dcal )
+recompute_first_of_month_offset(GncDenseCal *dcal)
{
- GDate *tmpDate;
+ GDate *tmpDate;
- tmpDate = g_date_new_dmy( 1, dcal->month, dcal->year );
- dcal->firstOfMonthOffset = g_date_get_weekday( tmpDate ) % 7;
- g_date_free( tmpDate );
+ tmpDate = g_date_new_dmy(1, dcal->month, dcal->year);
+ dcal->firstOfMonthOffset = g_date_get_weekday(tmpDate) % 7;
+ g_date_free(tmpDate);
}
void
-gnc_dense_cal_set_month( GncDenseCal *dcal, GDateMonth mon )
+gnc_dense_cal_set_month(GncDenseCal *dcal, GDateMonth mon)
{
- dcal->month = mon;
- recompute_first_of_month_offset( dcal );
- recompute_extents( dcal );
- if ( GTK_WIDGET_REALIZED( dcal ) ) {
- recompute_x_y_scales( dcal );
- gnc_dense_cal_draw_to_buffer( dcal );
- gtk_widget_queue_draw( GTK_WIDGET(dcal) );
- }
+ dcal->month = mon;
+ recompute_first_of_month_offset(dcal);
+ recompute_extents(dcal);
+ if (GTK_WIDGET_REALIZED(dcal))
+ {
+ recompute_x_y_scales(dcal);
+ gnc_dense_cal_draw_to_buffer(dcal);
+ gtk_widget_queue_draw(GTK_WIDGET(dcal));
+ }
}
void
-gnc_dense_cal_set_year( GncDenseCal *dcal, guint year )
+gnc_dense_cal_set_year(GncDenseCal *dcal, guint year)
{
- dcal->year = year;
- recompute_first_of_month_offset( dcal );
- recompute_extents( dcal );
- if ( GTK_WIDGET_REALIZED( dcal ) ) {
- recompute_x_y_scales( dcal );
- gnc_dense_cal_draw_to_buffer( dcal );
- gtk_widget_queue_draw( GTK_WIDGET(dcal) );
- }
+ dcal->year = year;
+ recompute_first_of_month_offset(dcal);
+ recompute_extents(dcal);
+ if (GTK_WIDGET_REALIZED(dcal))
+ {
+ recompute_x_y_scales(dcal);
+ gnc_dense_cal_draw_to_buffer(dcal);
+ gtk_widget_queue_draw(GTK_WIDGET(dcal));
+ }
}
void
-gnc_dense_cal_set_num_months( GncDenseCal *dcal, guint num_months )
+gnc_dense_cal_set_num_months(GncDenseCal *dcal, guint num_months)
{
- dcal->numMonths = num_months;
- recompute_extents( dcal );
- recompute_mark_storage( dcal );
- if ( GTK_WIDGET_REALIZED( dcal ) ) {
- recompute_x_y_scales( dcal );
- gnc_dense_cal_draw_to_buffer( dcal );
- gtk_widget_queue_draw( GTK_WIDGET(dcal) );
- }
+ dcal->numMonths = num_months;
+ recompute_extents(dcal);
+ recompute_mark_storage(dcal);
+ if (GTK_WIDGET_REALIZED(dcal))
+ {
+ recompute_x_y_scales(dcal);
+ gnc_dense_cal_draw_to_buffer(dcal);
+ gtk_widget_queue_draw(GTK_WIDGET(dcal));
+ }
}
void
-gnc_dense_cal_set_months_per_col( GncDenseCal *dcal, guint monthsPerCol )
+gnc_dense_cal_set_months_per_col(GncDenseCal *dcal, guint monthsPerCol)
{
- dcal->monthsPerCol = monthsPerCol;
- recompute_x_y_scales(dcal);
+ dcal->monthsPerCol = monthsPerCol;
+ recompute_x_y_scales(dcal);
}
guint
-gnc_dense_cal_get_num_months( GncDenseCal *dcal )
+gnc_dense_cal_get_num_months(GncDenseCal *dcal)
{
- return dcal->numMonths;
+ return dcal->numMonths;
}
GDateMonth
-gnc_dense_cal_get_month( GncDenseCal *dcal )
+gnc_dense_cal_get_month(GncDenseCal *dcal)
{
- return dcal->month;
+ return dcal->month;
}
GDateYear
-gnc_dense_cal_get_year( GncDenseCal *dcal )
+gnc_dense_cal_get_year(GncDenseCal *dcal)
{
- return dcal->year;
+ return dcal->year;
}
static void
gnc_dense_cal_dispose (GObject *object)
{
- int i;
- GncDenseCal *dcal;
- g_return_if_fail (object != NULL);
- g_return_if_fail (GNC_IS_DENSE_CAL (object));
+ int i;
+ GncDenseCal *dcal;
+ g_return_if_fail(object != NULL);
+ g_return_if_fail(GNC_IS_DENSE_CAL(object));
- dcal = GNC_DENSE_CAL(object);
+ dcal = GNC_DENSE_CAL(object);
- if(dcal->disposed)
- return;
+ if (dcal->disposed)
+ return;
+ dcal->disposed = TRUE;
- dcal->disposed = TRUE;
+ if (GTK_WIDGET_REALIZED(dcal->transPopup))
+ {
+ gtk_widget_hide(GTK_WIDGET(dcal->transPopup));
+ gtk_widget_destroy(GTK_WIDGET(dcal->transPopup));
+ dcal->transPopup = NULL;
+ }
- if ( GTK_WIDGET_REALIZED( dcal->transPopup ) ) {
- gtk_widget_hide( GTK_WIDGET(dcal->transPopup) );
- gtk_widget_destroy( GTK_WIDGET(dcal->transPopup) );
- dcal->transPopup = NULL;
- }
+ if (dcal->drawbuf)
+ {
+ g_object_unref(dcal->drawbuf);
+ dcal->drawbuf = NULL;
+ }
- if ( dcal->drawbuf ) {
- g_object_unref( dcal->drawbuf );
- dcal->drawbuf = NULL;
- }
+ /* FIXME: we have a bunch of cleanup to do, here. */
+ /* monthLabelFont, dayLabelFont */
+ if (dcal->monthLabelFont)
+ {
+ gdk_font_unref(dcal->monthLabelFont);
+ dcal->monthLabelFont = NULL;
+ }
- /* FIXME: we have a bunch of cleanup to do, here. */
- /* monthLabelFont, dayLabelFont */
- if ( dcal->monthLabelFont ) {
- gdk_font_unref( dcal->monthLabelFont );
- dcal->monthLabelFont = NULL;
- }
- if ( dcal->dayLabelFont ) {
- gdk_font_unref( dcal->dayLabelFont );
- dcal->dayLabelFont = NULL;
- }
- /* month labels */
- if ( dcal->monthLabels[0] ) {
- for ( i=0; i < 12; i++ ) {
- g_object_unref( dcal->monthLabels[i] );
- dcal->monthLabels[i] = NULL;
- }
- }
- /* mark data */
- gdc_free_all_mark_data( dcal );
+ if (dcal->dayLabelFont)
+ {
+ gdk_font_unref(dcal->dayLabelFont);
+ dcal->dayLabelFont = NULL;
+ }
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
+ /* month labels */
+ if (dcal->monthLabels[0])
+ {
+ for (i=0; i < 12; i++)
+ {
+ g_object_unref(dcal->monthLabels[i]);
+ dcal->monthLabels[i] = NULL;
+ }
+ }
+ gdc_free_all_mark_data(dcal);
+
+ g_object_unref(G_OBJECT(dcal->model));
+
+ if (G_OBJECT_CLASS (parent_class)->dispose)
+ G_OBJECT_CLASS(parent_class)->dispose(object);
}
static void
gnc_dense_cal_finalize (GObject *object)
{
- GncDenseCal *dcal;
- g_return_if_fail (object != NULL);
- g_return_if_fail (GNC_IS_DENSE_CAL (object));
+ GncDenseCal *dcal;
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNC_IS_DENSE_CAL (object));
- dcal = GNC_DENSE_CAL(object);
+ dcal = GNC_DENSE_CAL(object);
- if (G_OBJECT_CLASS (parent_class)->finalize)
- (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ G_OBJECT_CLASS(parent_class)->finalize(object);
}
static void
gnc_dense_cal_realize (GtkWidget *widget)
{
- GncDenseCal *dcal;
- GdkWindowAttr attributes;
- gint attributes_mask;
+ GncDenseCal *dcal;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
- g_return_if_fail (widget != NULL);
- g_return_if_fail (GNC_IS_DENSE_CAL (widget));
+ g_return_if_fail(widget != NULL);
+ g_return_if_fail(GNC_IS_DENSE_CAL (widget));
- GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
- dcal = GNC_DENSE_CAL (widget);
+ GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+ dcal = GNC_DENSE_CAL(widget);
- attributes.x = widget->allocation.x;
- attributes.y = widget->allocation.y;
- attributes.width = widget->allocation.width;
- attributes.height = widget->allocation.height;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.event_mask =
- gtk_widget_get_events (widget)
- | GDK_EXPOSURE_MASK
- | GDK_BUTTON_PRESS_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_POINTER_MOTION_MASK
- | GDK_POINTER_MOTION_HINT_MASK;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask =
+ gtk_widget_get_events(widget)
+ | GDK_EXPOSURE_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK;
+ attributes.visual = gtk_widget_get_visual(widget);
+ attributes.colormap = gtk_widget_get_colormap(widget);
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
- widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
+ widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask);
- widget->style = gtk_style_attach (widget->style, widget->window);
+ widget->style = gtk_style_attach(widget->style, widget->window);
- gdk_window_set_user_data (widget->window, widget);
+ gdk_window_set_user_data(widget->window, widget);
- gdc_reconfig( dcal );
+ gdc_reconfig(dcal);
- gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+ gtk_style_set_background(widget->style, widget->window, GTK_STATE_ACTIVE);
}
-static
-void
-gdc_reconfig( GncDenseCal *dcal )
+static void
+gdc_reconfig(GncDenseCal *dcal)
{
- GtkWidget *widget = GTK_WIDGET(dcal);
+ GtkWidget *widget = GTK_WIDGET(dcal);
- if ( dcal->drawbuf ) {
- g_object_unref( dcal->drawbuf );
- }
- dcal->drawbuf = gdk_pixmap_new( widget->window,
- widget->allocation.width,
- widget->allocation.height,
- -1 );
- gnc_dense_cal_draw_to_buffer( dcal );
+ if (dcal->drawbuf)
+ g_object_unref(dcal->drawbuf);
+ dcal->drawbuf = gdk_pixmap_new(widget->window,
+ widget->allocation.width,
+ widget->allocation.height,
+ -1);
+ gnc_dense_cal_draw_to_buffer(dcal);
}
static void
-gnc_dense_cal_size_request( GtkWidget *widget,
- GtkRequisition *requisition )
+gnc_dense_cal_size_request(GtkWidget *widget,
+ GtkRequisition *requisition)
{
- GncDenseCal *dcal = GNC_DENSE_CAL(widget);
- if ( !dcal->initialized ) {
- PERR( "Uninitialized size request\n" );
- requisition->width = DENSE_CAL_DEFAULT_WIDTH;
- requisition->height = DENSE_CAL_DEFAULT_HEIGHT;
- return;
- }
- requisition->width =
- (dcal->leftPadding * 2)
- + (num_cols(dcal) * (col_width_at(dcal, dcal->min_x_scale)
- + dcal->label_width))
- + ((num_cols(dcal)-1) * COL_BORDER_SIZE);
- requisition->height =
- (dcal->topPadding * 2)
- + MINOR_BORDER_SIZE
- + dcal->dayLabelHeight
- + (num_weeks_per_col(dcal)
- * week_height_at(dcal, dcal->min_y_scale));
+ GncDenseCal *dcal = GNC_DENSE_CAL(widget);
+ if (!dcal->initialized)
+ {
+ PERR("Uninitialized size request\n");
+ requisition->width = DENSE_CAL_DEFAULT_WIDTH;
+ requisition->height = DENSE_CAL_DEFAULT_HEIGHT;
+ return;
+ }
+ requisition->width =
+ (dcal->leftPadding * 2)
+ + (num_cols(dcal)* (col_width_at(dcal, dcal->min_x_scale)
+ + dcal->label_width))
+ + ((num_cols(dcal)-1) * COL_BORDER_SIZE);
+ requisition->height =
+ (dcal->topPadding * 2)
+ + MINOR_BORDER_SIZE
+ + dcal->dayLabelHeight
+ + (num_weeks_per_col(dcal)
+ * week_height_at(dcal, dcal->min_y_scale));
}
static void
-recompute_x_y_scales( GncDenseCal *dcal )
+recompute_x_y_scales(GncDenseCal *dcal)
{
- GtkWidget *widget;
- int denom;
- int width, height;
+ GtkWidget *widget;
+ int denom;
+ int width, height;
- widget = GTK_WIDGET(dcal);
+ widget = GTK_WIDGET(dcal);
- width = DENSE_CAL_DEFAULT_WIDTH;
- height = DENSE_CAL_DEFAULT_HEIGHT;
- if ( dcal->initialized ) {
- width = widget->allocation.width;
- height = widget->allocation.height;
- }
+ width = DENSE_CAL_DEFAULT_WIDTH;
+ height = DENSE_CAL_DEFAULT_HEIGHT;
+ if (dcal->initialized)
+ {
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+ }
- /* FIXME: there's something slightly wrong in the x_scale computation that
- * lets us draw larger than our area. */
- denom = 7 * num_cols(dcal);
- g_assert( denom != 0 );
- dcal->x_scale = (gint)((width
- - (dcal->leftPadding * 2)
- - (num_cols(dcal) * ( (8 * MINOR_BORDER_SIZE)
- + dcal->label_width ))
- - ((num_cols(dcal)-1) * COL_BORDER_SIZE))
- / denom);
- dcal->x_scale = MAX( dcal->x_scale, dcal->min_x_scale );
+ /* FIXME: there's something slightly wrong in the x_scale computation that
+ * lets us draw larger than our area. */
+ denom = 7 * num_cols(dcal);
+ g_assert(denom != 0);
+ dcal->x_scale = (gint)((width
+ - (dcal->leftPadding * 2)
+ - (num_cols(dcal) * ((8 * MINOR_BORDER_SIZE)
+ + dcal->label_width))
+ - ((num_cols(dcal)-1) * COL_BORDER_SIZE))
+ / denom);
+ dcal->x_scale = MAX(dcal->x_scale, dcal->min_x_scale);
- denom = num_weeks_per_col(dcal);
- g_assert( denom != 0 );
- dcal->y_scale = (gint)((height
- - (dcal->topPadding * 2)
- - MINOR_BORDER_SIZE
- - dcal->dayLabelHeight
- - (num_weeks_per_col(dcal)-1
- * MINOR_BORDER_SIZE))
- / denom );
- dcal->y_scale = MAX( dcal->y_scale, dcal->min_y_scale );
+ denom = num_weeks_per_col(dcal);
+ g_assert(denom != 0);
+ dcal->y_scale = (gint)((height
+ - (dcal->topPadding * 2)
+ - MINOR_BORDER_SIZE
+ - dcal->dayLabelHeight
+ - (num_weeks_per_col(dcal)-1
+ * MINOR_BORDER_SIZE))
+ / denom);
+ dcal->y_scale = MAX(dcal->y_scale, dcal->min_y_scale);
}
static void
-gdc_free_all_mark_data( GncDenseCal *dcal )
+gdc_free_all_mark_data(GncDenseCal *dcal)
{
- int i;
- GList *l;
- for ( i=0; i < dcal->numMarks; i++ ) {
- /* Each of these just contains an elt of dcal->markData,
- * which we're about to free, below... */
- g_list_free( dcal->marks[i] );
- }
- g_free( dcal->marks );
- dcal->marks = NULL;
- /* Remove the old mark data. */
- for ( l = dcal->markData; l; l = l->next ) {
- g_list_free( ((gdc_mark_data*)l->data)->ourMarks );
- g_free( (gdc_mark_data*)l->data );
- }
- g_list_free( dcal->markData );
- dcal->markData = NULL;
+ int i;
+ GList *l;
+ for (i=0; i < dcal->numMarks; i++)
+ {
+ /* Each of these just contains an elt of dcal->markData,
+ * which we're about to free, below... */
+ g_list_free(dcal->marks[i]);
+ }
+ g_free(dcal->marks);
+ dcal->marks = NULL;
+ /* Remove the old mark data. */
+ for (l = dcal->markData; l; l = l->next)
+ {
+ g_list_free(((gdc_mark_data*)l->data)->ourMarks);
+ g_free((gdc_mark_data*)l->data);
+ }
+ g_list_free(dcal->markData);
+ dcal->markData = NULL;
}
static void
-recompute_mark_storage( GncDenseCal *dcal )
+recompute_mark_storage(GncDenseCal *dcal)
{
- if ( dcal->marks == NULL ) {
- goto createNew;
- }
+ if (dcal->marks == NULL)
+ goto createNew;
+ gdc_free_all_mark_data(dcal);
- gdc_free_all_mark_data( dcal );
createNew:
- dcal->numMarks = num_weeks(dcal) * 7;
- dcal->marks = g_new0( GList*, dcal->numMarks );
- g_signal_emit_by_name( dcal, MARKS_LOST_SIGNAL_NAME );
+ dcal->numMarks = num_weeks(dcal) * 7;
+ dcal->marks = g_new0(GList*, dcal->numMarks);
+ if (dcal->model)
+ gdc_add_markings(dcal);
}
static void
-recompute_extents( GncDenseCal *dcal )
+recompute_extents(GncDenseCal *dcal)
{
- GDate date;
- gint start_week, end_week;
+ GDate date;
+ gint start_week, end_week;
- g_date_clear( &date, 1 );
- g_date_set_dmy( &date, 1, dcal->month, dcal->year );
- start_week = g_date_get_sunday_week_of_year(&date);
- g_date_add_months( &date, dcal->numMonths );
- end_week = g_date_get_sunday_week_of_year(&date);
- if ( g_date_get_year(&date) != dcal->year ) {
- end_week += g_date_get_sunday_weeks_in_year( dcal->year );
- }
- dcal->num_weeks = end_week - start_week + 1;
+ g_date_clear(&date, 1);
+ g_date_set_dmy(&date, 1, dcal->month, dcal->year);
+ start_week = g_date_get_sunday_week_of_year(&date);
+ g_date_add_months(&date, dcal->numMonths);
+ end_week = g_date_get_sunday_week_of_year(&date);
+ if (g_date_get_year(&date) != dcal->year)
+ end_week += g_date_get_sunday_weeks_in_year(dcal->year);
+ dcal->num_weeks = end_week - start_week + 1;
}
static void
-gnc_dense_cal_size_allocate( GtkWidget *widget,
- GtkAllocation *allocation )
+gnc_dense_cal_size_allocate(GtkWidget *widget,
+ GtkAllocation *allocation)
{
- GncDenseCal *dcal;
+ GncDenseCal *dcal;
- g_return_if_fail (widget != NULL);
- g_return_if_fail (GNC_IS_DENSE_CAL (widget));
- g_return_if_fail (allocation != NULL);
+ g_return_if_fail(widget != NULL);
+ g_return_if_fail(GNC_IS_DENSE_CAL (widget));
+ g_return_if_fail(allocation != NULL);
- dcal = GNC_DENSE_CAL(widget);
+ dcal = GNC_DENSE_CAL(widget);
- widget->allocation = *allocation;
+ widget->allocation = *allocation;
- if (GTK_WIDGET_REALIZED (widget)) {
- gdk_window_move_resize (widget->window,
- allocation->x, allocation->y,
- allocation->width,
- allocation->height);
+ if (GTK_WIDGET_REALIZED(widget)) {
+ gdk_window_move_resize(widget->window,
+ allocation->x, allocation->y,
+ allocation->width,
+ allocation->height);
+
+ /* We want to know how many px we can increase every day
+ * [width] or week [height]. */
+ recompute_x_y_scales(dcal);
- /* We want to know how many px we can increase every day
- * [width] or week [height]. */
- recompute_x_y_scales( dcal );
-
- gdc_reconfig( dcal );
- }
+ gdc_reconfig(dcal);
+ }
}
static void
-free_rect( gpointer data, gpointer ud )
+free_rect(gpointer data, gpointer ud)
{
- g_free( (GdkRectangle*)data );
+ g_free((GdkRectangle*)data);
}
static gint
-gnc_dense_cal_expose( GtkWidget *widget,
- GdkEventExpose *event )
+gnc_dense_cal_expose(GtkWidget *widget,
+ GdkEventExpose *event)
{
- GncDenseCal *dcal;
- GdkGC *gc;
+ GncDenseCal *dcal;
+ GdkGC *gc;
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GNC_IS_DENSE_CAL (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
+ g_return_val_if_fail(widget != NULL, FALSE);
+ g_return_val_if_fail(GNC_IS_DENSE_CAL(widget), FALSE);
+ g_return_val_if_fail(event != NULL, FALSE);
- if (event->count > 0)
- return FALSE;
+ if (event->count > 0)
+ return FALSE;
- dcal = GNC_DENSE_CAL (widget);
- gc = widget->style->fg_gc[ GTK_WIDGET_STATE(widget) ];
- gdk_draw_drawable(GDK_DRAWABLE(widget->window),
- gc,
- GDK_DRAWABLE(dcal->drawbuf),
- 0, 0, 0, 0,
- widget->allocation.width,
- widget->allocation.height);
+ dcal = GNC_DENSE_CAL(widget);
+ gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
+ gdk_draw_drawable(GDK_DRAWABLE(widget->window),
+ gc,
+ GDK_DRAWABLE(dcal->drawbuf),
+ 0, 0, 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
- return FALSE;
+ return FALSE;
}
static void
-gnc_dense_cal_draw_to_buffer( GncDenseCal *dcal )
+gnc_dense_cal_draw_to_buffer(GncDenseCal *dcal)
{
- GtkWidget *widget;
- gint i;
- int maxWidth;
+ GtkWidget *widget;
+ gint i;
+ int maxWidth;
- widget = &dcal->widget;
+ widget = &dcal->widget;
- if ( ! dcal->drawbuf )
- return;
+ if (!dcal->drawbuf)
+ return;
- gdk_draw_rectangle (dcal->drawbuf,
- widget->style->white_gc,
- TRUE,
- 0, 0,
- widget->allocation.width,
- widget->allocation.height);
+ gdk_draw_rectangle(dcal->drawbuf,
+ widget->style->white_gc,
+ TRUE,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
- if ( dcal->needInitMonthLabels ) {
- /* Create the month labels */
- gint i;
- GdkPixmap *tmpPix;
- GdkImage *tmpImg;
- GdkGC *gc;
- GdkColor black;
+ if (dcal->needInitMonthLabels)
+ {
+ /* Create the month labels */
+ gint i;
+ GdkPixmap *tmpPix;
+ GdkImage *tmpImg;
+ GdkGC *gc;
+ GdkColor black;
- gc = widget->style->fg_gc[widget->state];
- tmpPix = gdk_pixmap_new( NULL,
- dcal->label_height,
- dcal->label_width,
- gdk_visual_get_system()->depth );
- black.pixel = gdk_rgb_xpixel_from_rgb(0);
- for ( i=0; i<12; i++ ) {
- guint x,y;
- /* these are going to be rotated, so transpose width
- * and height */
- dcal->monthLabels[i] =
- gdk_pixmap_new( widget->window,
- dcal->label_width,
- dcal->label_height, -1 );
- gdk_draw_rectangle( dcal->monthLabels[i],
- widget->style->white_gc,
- TRUE, 0, 0,
- dcal->label_width,
- dcal->label_height );
+ gc = widget->style->fg_gc[widget->state];
+ tmpPix = gdk_pixmap_new(NULL,
+ dcal->label_height,
+ dcal->label_width,
+ gdk_visual_get_system()->depth);
+ black.pixel = gdk_rgb_xpixel_from_rgb(0);
+ for (i=0; i<12; i++)
+ {
+ guint x,y;
+ /* these are going to be rotated, so transpose width
+ * and height */
+ dcal->monthLabels[i] =
+ gdk_pixmap_new(widget->window,
+ dcal->label_width,
+ dcal->label_height, -1);
+ gdk_draw_rectangle(dcal->monthLabels[i],
+ widget->style->white_gc,
+ TRUE, 0, 0,
+ dcal->label_width,
+ dcal->label_height);
- gdk_draw_rectangle( tmpPix,
- widget->style->white_gc,
- TRUE, 0, 0,
- dcal->label_height,
- dcal->label_width );
+ gdk_draw_rectangle(tmpPix,
+ widget->style->white_gc,
+ TRUE, 0, 0,
+ dcal->label_height,
+ dcal->label_width);
- gdk_draw_string( tmpPix, dcal->monthLabelFont, gc,
- dcal->label_lbearing,
- dcal->label_ascent,
- month_name(i) );
+ gdk_draw_string(tmpPix, dcal->monthLabelFont, gc,
+ dcal->label_lbearing,
+ dcal->label_ascent,
+ month_name(i));
- tmpImg = gdk_image_get( tmpPix, 0, 0,
- dcal->label_height,
- dcal->label_width );
+ tmpImg = gdk_image_get(tmpPix, 0, 0,
+ dcal->label_height,
+ dcal->label_width);
- /* now, (transpose the pixel matrix)==(do a 90-degree
- * counter-clockwise rotation) */
- for ( x=0; x < dcal->label_height; x++ ) {
- for ( y=0; y < dcal->label_width; y++ ) {
- if ( gdk_image_get_pixel( tmpImg, x, y )
- != black.pixel ) {
- continue;
- }
- gdk_draw_point( dcal->monthLabels[i],
- gc, y,
- dcal->label_height - x );
- }
- }
- gdk_image_destroy( tmpImg );
- }
- dcal->needInitMonthLabels = FALSE;
- }
+ /* now, (transpose the pixel matrix)==(do a 90-degree
+ * counter-clockwise rotation) */
+ for (x=0; x < dcal->label_height; x++)
+ {
+ for (y=0; y < dcal->label_width; y++)
+ {
+ if (gdk_image_get_pixel(tmpImg, x, y) != black.pixel)
+ continue;
+ gdk_draw_point(dcal->monthLabels[i],
+ gc, y,
+ dcal->label_height - x);
+ }
+ }
+ gdk_image_destroy(tmpImg);
+ }
+ dcal->needInitMonthLabels = FALSE;
+ }
- /* Fill in alternating month colors. */
- {
- gint i;
- GdkGC *gc;
- GdkRectangle *rect;
- GList *mcList, *mcListIter;
+ /* Fill in alternating month colors. */
+ {
+ gint i;
+ GdkGC *gc;
+ GdkRectangle *rect;
+ GList *mcList, *mcListIter;
- gc = gdk_gc_new( dcal->widget.window );
- gdk_gc_copy( gc, widget->style->fg_gc[GTK_WIDGET_STATE(widget)] );
+ gc = gdk_gc_new(dcal->widget.window);
+ gdk_gc_copy(gc, widget->style->fg_gc[GTK_WIDGET_STATE(widget)]);
- /* reset all of the month position offsets. */
- for ( i=0; i<12; i++ ) {
- dcal->monthPositions[i].x = dcal->monthPositions[i].y = -1;
- }
+ /* reset all of the month position offsets. */
+ for (i=0; i<12; i++)
+ {
+ dcal->monthPositions[i].x = dcal->monthPositions[i].y = -1;
+ }
- /* Paint the weeks for the upcoming N months. */
- for ( i=0; i < dcal->numMonths; i++ ) {
- gdk_gc_set_foreground( gc, &dcal->weekColors[ i % 2 ] );
+ /* Paint the weeks for the upcoming N months. */
+ for (i=0; i < dcal->numMonths; i++)
+ {
+ gdk_gc_set_foreground(gc, &dcal->weekColors[ i % 2 ]);
- mcList = NULL;
- month_coords( dcal, i, &mcList );
- dcal->monthPositions[i].x =
- floor(i/dcal->monthsPerCol)
- * (col_width(dcal) + COL_BORDER_SIZE);
- dcal->monthPositions[i].y = ((GdkRectangle*)mcList->next->data)->y;
- for ( mcListIter = mcList; mcListIter;
- mcListIter = mcListIter->next ) {
- rect = (GdkRectangle*)mcListIter->data;
- gdk_draw_rectangle( dcal->drawbuf, gc,
- TRUE, rect->x, rect->y,
- rect->width - 2, rect->height );
- }
- g_list_foreach( mcList, free_rect, NULL );
- g_list_free( mcList );
- }
+ mcList = NULL;
+ month_coords(dcal, i, &mcList);
+ dcal->monthPositions[i].x
+ = floor(i/dcal->monthsPerCol)
+ * (col_width(dcal) + COL_BORDER_SIZE);
+ dcal->monthPositions[i].y = ((GdkRectangle*)mcList->next->data)->y;
+ for (mcListIter = mcList; mcListIter != NULL; mcListIter = mcListIter->next)
+ {
+ rect = (GdkRectangle*)mcListIter->data;
+ gdk_draw_rectangle(dcal->drawbuf, gc,
+ TRUE, rect->x, rect->y,
+ rect->width - 2, rect->height);
+ }
+ g_list_foreach(mcList, free_rect, NULL);
+ g_list_free(mcList);
+ }
- gdk_gc_destroy( gc );
- }
+ gdk_gc_destroy(gc);
+ }
- /* Hilight the marked days. */
- {
- int i;
- int x1, x2, y1, y2;
- GdkColor markColor, black;
- GList *l;
- gdc_mark_data *gdcmd;
+ /* Hilight the marked days. */
+ {
+ int i;
+ int x1, x2, y1, y2;
+ GdkColor markColor, black;
- gdk_color_parse( MARK_COLOR, &markColor );
- gdk_colormap_alloc_color( gdk_colormap_get_system(), &markColor, TRUE, TRUE );
- gdk_color_black( gdk_colormap_get_system(), &black );
+ gdk_color_parse(MARK_COLOR, &markColor);
+ gdk_colormap_alloc_color(gdk_colormap_get_system(), &markColor, TRUE, TRUE);
+ gdk_color_black(gdk_colormap_get_system(), &black);
- /* FIXME: use a different GC for this */
- gdk_gc_set_foreground( widget->style->fg_gc[widget->state], &markColor );
- for ( i=0; i<dcal->numMarks; i++ ) {
- for ( l = dcal->marks[i]; l ; l = l->next ) {
- gdcmd = (gdc_mark_data*)l->data;
- doc_coords( dcal, i, &x1, &y1, &x2, &y2 );
- gdk_draw_rectangle( dcal->drawbuf,
- widget->style->fg_gc[widget->state],
- TRUE, x1, y1, (x2-x1), (y2-y1) );
- }
- }
- gdk_gc_set_foreground( widget->style->fg_gc[widget->state], &black );
- }
+ /* FIXME: use a different GC for this */
+ gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &markColor);
+ for (i=0; i<dcal->numMarks; i++)
+ {
+ if (dcal->marks[i] != NULL)
+ {
+ doc_coords(dcal, i, &x1, &y1, &x2, &y2);
+ gdk_draw_rectangle(dcal->drawbuf,
+ widget->style->fg_gc[widget->state],
+ TRUE, x1, y1, (x2-x1), (y2-y1));
+ }
+ }
+ gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &black);
+ }
- for ( i=0; i < num_cols(dcal); i++ ) {
- gint x, y, w, h;
- gint j;
+ for (i=0; i < num_cols(dcal); i++)
+ {
+ gint x, y, w, h;
+ gint j;
- dcal->dayLabelHeight = gdk_string_height( dcal->monthLabelFont, "S" );
+ dcal->dayLabelHeight = gdk_string_height(dcal->monthLabelFont, "S");
- x = dcal->leftPadding
- + ( i * (col_width(dcal)+COL_BORDER_SIZE) )
- + dcal->label_width;
- y = dcal->topPadding + dcal->dayLabelHeight;
- w = col_width(dcal) - COL_BORDER_SIZE - dcal->label_width - 2;
- h = col_height(dcal);
+ x = dcal->leftPadding
+ + (i * (col_width(dcal)+COL_BORDER_SIZE))
+ + dcal->label_width;
+ y = dcal->topPadding + dcal->dayLabelHeight;
+ w = col_width(dcal) - COL_BORDER_SIZE - dcal->label_width - 2;
+ h = col_height(dcal);
- /* draw the outside border [inside the month labels] */
- gdk_draw_rectangle( dcal->drawbuf,
+ /* draw the outside border [inside the month labels] */
+ gdk_draw_rectangle(dcal->drawbuf,
+ widget->style->fg_gc[widget->state],
+ FALSE, x, y, w, h);
+ /* draw the week seperations */
+ for (j=0; j < num_weeks_per_col(dcal); j++)
+ {
+ gint wy = y + (j * week_height(dcal));
+ gdk_draw_line(dcal->drawbuf,
+ widget->style->fg_gc[widget->state],
+ x, wy,
+ x + w, wy);
+ }
+
+ /* draw the day seperations */
+ for (j=1; j<7; j++)
+ {
+ gint dx = x + (j * day_width(dcal));
+ gdk_draw_line(dcal->drawbuf,
+ widget->style->fg_gc[widget->state],
+ dx, y,
+ dx, y + col_height(dcal));
+ }
+
+ /* draw the day labels */
+ maxWidth = gdk_string_width(dcal->monthLabelFont, "88");
+ if (dcal->x_scale > maxWidth)
+ {
+ for (j=0; j<7; j++)
+ {
+ gint dx = x
+ + (j * day_width(dcal))
+ + (day_width(dcal)/2)
+ - (gdk_string_width(dcal->monthLabelFont,
+ day_label(j)) / 2);
+ gint dy = y - 2;
+ gdk_draw_string(dcal->drawbuf,
+ dcal->monthLabelFont,
widget->style->fg_gc[widget->state],
- FALSE, x, y, w, h );
- /* draw the week seperations */
- {
- for ( j=0; j < num_weeks_per_col(dcal); j++ ) {
- gint wy = y + (j * week_height(dcal));
- gdk_draw_line( dcal->drawbuf,
- widget->style->fg_gc[widget->state],
- x, wy,
- x + w, wy );
- }
- }
- /* draw the day seperations */
- {
- for ( j=1; j<7; j++ ) {
- gint dx = x + (j * day_width(dcal));
- gdk_draw_line( dcal->drawbuf,
- widget->style->fg_gc[widget->state],
- dx, y,
- dx, y + col_height(dcal) );
- }
- }
- /* draw the day labels */
- maxWidth = gdk_string_width( dcal->monthLabelFont, "88" );
- if ( dcal->x_scale > maxWidth ) {
- for ( j=0; j<7; j++ ) {
- gint dx = x
- + (j * day_width(dcal))
- + (day_width(dcal)/2)
- - ( gdk_string_width(dcal->monthLabelFont,
- day_label(j)) / 2 );
- gint dy = y - 2;
- gdk_draw_string( dcal->drawbuf,
- dcal->monthLabelFont,
- widget->style->fg_gc[widget->state],
- dx, dy, day_label(j) );
- }
- }
- }
+ dx, dy, day_label(j));
+ }
+ }
+ }
- /* Try some pixmap copying for the month labels. */
- {
- gint i, idx;
+ /* Try some pixmap copying for the month labels. */
+ {
+ gint i, idx;
- for ( i=0; i<12; i++ ) {
- if ( dcal->monthPositions[i].x == -1 ) {
- break;
- }
- idx = (dcal->month - 1 + i) % 12;
- gdk_draw_drawable(GDK_DRAWABLE(dcal->drawbuf),
- widget->style->fg_gc[widget->state],
- GDK_DRAWABLE(dcal->monthLabels[idx]),
- 0, 0,
- dcal->leftPadding
- + dcal->monthPositions[i].x,
- dcal->monthPositions[i].y,
- dcal->label_width, dcal->label_height);
- }
- }
+ for (i=0; i<12; i++)
+ {
+ if (dcal->monthPositions[i].x == -1)
+ break;
+ idx = (dcal->month - 1 + i) % 12;
+ gdk_draw_drawable(GDK_DRAWABLE(dcal->drawbuf),
+ widget->style->fg_gc[widget->state],
+ GDK_DRAWABLE(dcal->monthLabels[idx]),
+ 0, 0,
+ dcal->leftPadding
+ + dcal->monthPositions[i].x,
+ dcal->monthPositions[i].y,
+ dcal->label_width, dcal->label_height);
+ }
+ }
- /* Try the per-day strings [dates] */
- {
- GDate d, eoc;
- gint doc;
- gchar dayNumBuf[3];
- gint numW, numH;
- gint x1, y1, x2, y2, w, h;
+ /* Try the per-day strings [dates] */
+ {
+ GDate d, eoc;
+ gint doc;
+ gchar dayNumBuf[3];
+ gint numW, numH;
+ gint x1, y1, x2, y2, w, h;
- g_date_set_dmy( &d, 1, dcal->month, dcal->year );
- eoc = d;
- g_date_add_months( &eoc, dcal->numMonths );
- for ( doc = 0; g_date_get_julian(&d) < g_date_get_julian(&eoc);
- g_date_add_days( &d, 1 ), doc++ ) {
- doc_coords( dcal, doc, &x1, &y1, &x2, &y2 );
- memset( dayNumBuf, 0, 3 );
- snprintf( dayNumBuf, 3, "%d", g_date_get_day( &d ) );
- numW = gdk_string_width( dcal->dayLabelFont, dayNumBuf );
- numH = gdk_string_height( dcal->dayLabelFont, dayNumBuf );
- w = (x2 - x1)+1;
- h = (y2 - y1)+1;
- gdk_draw_string( dcal->drawbuf,
- dcal->dayLabelFont,
- widget->style->fg_gc[widget->state],
- x1 + (w/2) - (numW/2),
- y1 + (h/2) + (numH/2),
- dayNumBuf );
- }
- }
+ g_date_set_dmy(&d, 1, dcal->month, dcal->year);
+ eoc = d;
+ g_date_add_months(&eoc, dcal->numMonths);
+ for (doc = 0; g_date_get_julian(&d) < g_date_get_julian(&eoc); g_date_add_days(&d, 1), doc++)
+ {
+ doc_coords(dcal, doc, &x1, &y1, &x2, &y2);
+ memset(dayNumBuf, 0, 3);
+ snprintf(dayNumBuf, 3, "%d", g_date_get_day(&d));
+ numW = gdk_string_width(dcal->dayLabelFont, dayNumBuf);
+ numH = gdk_string_height(dcal->dayLabelFont, dayNumBuf);
+ w = (x2 - x1)+1;
+ h = (y2 - y1)+1;
+ gdk_draw_string(dcal->drawbuf,
+ dcal->dayLabelFont,
+ widget->style->fg_gc[widget->state],
+ x1 + (w/2) - (numW/2),
+ y1 + (h/2) + (numH/2),
+ dayNumBuf);
+ }
+ }
- {
- GdkRectangle update_rect;
- update_rect.x = 0;
- update_rect.y = 0;
- update_rect.width = widget->allocation.width;
- update_rect.height = widget->allocation.height;
- gtk_widget_draw( GTK_WIDGET(dcal),
- &update_rect );
- }
-
+ {
+ GdkRectangle update_rect;
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = widget->allocation.width;
+ update_rect.height = widget->allocation.height;
+ gtk_widget_draw(GTK_WIDGET(dcal), &update_rect);
+ }
}
static void
-populate_hover_window( GncDenseCal *dcal, gint doc )
+populate_hover_window(GncDenseCal *dcal, gint doc)
{
- GtkWidget *w;
- GDate *date;
- static const int MAX_STRFTIME_BUF_LEN = 64;
- gchar strftimeBuf[MAX_STRFTIME_BUF_LEN];
+ GtkWidget *w;
+ GDate *date;
+ static const int MAX_STRFTIME_BUF_LEN = 64;
+ gchar strftimeBuf[MAX_STRFTIME_BUF_LEN];
- if ( doc >= 0 ) {
- GObject *o;
- GtkCList *cl;
- GList *l;
- gchar *rowText[2];
- gint row = 0;
- gdc_mark_data *gdcmd;
+ if (doc >= 0)
+ {
+ GObject *o;
+ GtkListStore *model;
+ GList *l;
- w = GTK_WIDGET( g_object_get_data( G_OBJECT(dcal->transPopup),
- "dateLabel" ) );
- date = g_date_new_dmy( 1, dcal->month, dcal->year );
- g_date_add_days( date, doc );
- /* Note: the ISO date format (%F or equivalently
- * %Y-%m-%d) is not a good idea here since many
- * locales will want to use a very different date
- * format. Please leave the specification of the date
- * format up to the locale and use %x here. */
- g_date_strftime( strftimeBuf, MAX_STRFTIME_BUF_LEN-1, "%x", date );
- gtk_label_set_text( GTK_LABEL(w), strftimeBuf );
+ w = GTK_WIDGET(g_object_get_data(G_OBJECT(dcal->transPopup), "dateLabel"));
+ date = g_date_new_dmy(1, dcal->month, dcal->year);
+ g_date_add_days(date, doc);
+ /* Note: the ISO date format (%F or equivalently
+ * %Y-%m-%d) is not a good idea here since many
+ * locales will want to use a very different date
+ * format. Please leave the specification of the date
+ * format up to the locale and use %x here. */
+ g_date_strftime(strftimeBuf, MAX_STRFTIME_BUF_LEN-1, "%x", date);
+ gtk_label_set_text(GTK_LABEL(w), strftimeBuf);
- o = G_OBJECT(dcal->transPopup);
- cl = GTK_CLIST( g_object_get_data(o, "clist" ) );
- gtk_clist_clear( cl );
- for ( l = dcal->marks[doc]; l; l = l->next ) {
- gdcmd = (gdc_mark_data*)l->data;
- rowText[0] = ( gdcmd->name ? gdcmd->name : _("(unnamed)") );
- rowText[1] = gdcmd->info;
- gtk_clist_insert( cl, row++, rowText );
- }
+ o = G_OBJECT(dcal->transPopup);
+ model = GTK_LIST_STORE(g_object_get_data(o, "model"));
+ gtk_list_store_clear(model);
+ for (l = dcal->marks[doc]; l; l = l->next)
+ {
+ GtkTreeIter iter;
+ gdc_mark_data *gdcmd;
- // FIXME: free 'date'?
- }
+ gdcmd = (gdc_mark_data*)l->data;
+ gtk_list_store_insert(model, &iter, INT_MAX);
+ gtk_list_store_set(model, &iter, 0, (gdcmd->name ? gdcmd->name : _("(unnamed)")), 1, gdcmd->info, -1);
+ }
+
+ g_date_free(date);
+ }
}
static gint
-gnc_dense_cal_button_press( GtkWidget *widget,
- GdkEventButton *evt )
+gnc_dense_cal_button_press(GtkWidget *widget,
+ GdkEventButton *evt)
{
- gint doc;
- GncDenseCal *dcal = GNC_DENSE_CAL(widget);
+ gint doc;
+ GncDenseCal *dcal = GNC_DENSE_CAL(widget);
- doc = wheres_this( dcal, evt->x, evt->y );
- dcal->showPopup = ~(dcal->showPopup);
- if ( dcal->showPopup && doc >= 0 ) {
- // Do the move twice in case the WM is ignoring the first one
- // because the window hasn't been shown, yet. The WM is free
- // to ignore our move and place windows according to it's own
- // strategy, but hopefully it'll listen to us. Certainly the
- // second move after show_all'ing the window should do the
- // trick with a bit of flicker.
- gtk_window_move(GTK_WINDOW(dcal->transPopup), evt->x_root+5, evt->y_root+5);
- populate_hover_window( dcal, doc );
- gtk_widget_show_all( GTK_WIDGET(dcal->transPopup) );
- gtk_window_move(GTK_WINDOW(dcal->transPopup), evt->x_root+5, evt->y_root+5);
- } else {
- gtk_widget_hide( GTK_WIDGET(dcal->transPopup) );
- }
- return FALSE;
+ doc = wheres_this(dcal, evt->x, evt->y);
+ dcal->showPopup = ~(dcal->showPopup);
+ if (dcal->showPopup && doc >= 0)
+ {
+ // Do the move twice in case the WM is ignoring the first one
+ // because the window hasn't been shown, yet. The WM is free
+ // to ignore our move and place windows according to it's own
+ // strategy, but hopefully it'll listen to us. Certainly the
+ // second move after show_all'ing the window should do the
+ // trick with a bit of flicker.
+ gtk_window_move(GTK_WINDOW(dcal->transPopup), evt->x_root+5, evt->y_root+5);
+ populate_hover_window(dcal, doc);
+ gtk_widget_show_all(GTK_WIDGET(dcal->transPopup));
+ gtk_window_move(GTK_WINDOW(dcal->transPopup), evt->x_root+5, evt->y_root+5);
+ }
+ else
+ {
+ gtk_widget_hide(GTK_WIDGET(dcal->transPopup));
+ }
+ return FALSE;
}
static gint
-gnc_dense_cal_motion_notify( GtkWidget *widget,
- GdkEventMotion *event )
+gnc_dense_cal_motion_notify(GtkWidget *widget,
+ GdkEventMotion *event)
{
- GncDenseCal *dcal;
- gint doc;
- int unused;
- int x_root_offset, y_root_offset;
- GdkModifierType unused2;
+ GncDenseCal *dcal;
+ gint doc;
+ int unused;
+ int x_root_offset, y_root_offset;
+ GdkModifierType unused2;
- dcal = GNC_DENSE_CAL(widget);
- if ( ! dcal->showPopup )
- return FALSE;
+ dcal = GNC_DENSE_CAL(widget);
+ if (!dcal->showPopup)
+ return FALSE;
- x_root_offset = event->x_root;
- y_root_offset = event->y_root;
+ x_root_offset = event->x_root;
+ y_root_offset = event->y_root;
- /* As per http://www.gtk.org/tutorial/sec-eventhandling.html */
- if ( event->is_hint ) {
- gdk_window_get_pointer( event->window, &unused, &unused, &unused2 );
- }
- gdk_window_move( GTK_WIDGET(dcal->transPopup)->window,
- x_root_offset+5, y_root_offset+5 );
- doc = wheres_this( dcal, event->x, event->y );
- if ( doc >= 0 ) {
- populate_hover_window( dcal, doc );
- gtk_widget_show_all( GTK_WIDGET(dcal->transPopup) );
- } else {
- gtk_widget_hide( GTK_WIDGET(dcal->transPopup) );
- }
- return TRUE;
+ /* As per http://www.gtk.org/tutorial/sec-eventhandling.html */
+ if (event->is_hint)
+ gdk_window_get_pointer(event->window, &unused, &unused, &unused2);
+ gdk_window_move(GTK_WIDGET(dcal->transPopup)->window,
+ x_root_offset+5, y_root_offset+5);
+ doc = wheres_this(dcal, event->x, event->y);
+ if (doc >= 0)
+ {
+ populate_hover_window(dcal, doc);
+ gtk_widget_show_all(GTK_WIDGET(dcal->transPopup));
+ }
+ else
+ {
+ gtk_widget_hide(GTK_WIDGET(dcal->transPopup));
+ }
+ return TRUE;
}
static inline int
-day_width_at( GncDenseCal *dcal, guint xScale )
+day_width_at(GncDenseCal *dcal, guint xScale)
{
- return xScale + MINOR_BORDER_SIZE;
+ return xScale + MINOR_BORDER_SIZE;
}
static inline int
-day_width( GncDenseCal *dcal )
+day_width(GncDenseCal *dcal)
{
- return day_width_at( dcal, dcal->x_scale );
+ return day_width_at(dcal, dcal->x_scale);
}
static inline int
-day_height_at( GncDenseCal *dcal, guint yScale )
+day_height_at(GncDenseCal *dcal, guint yScale)
{
- return yScale + MINOR_BORDER_SIZE;
+ return yScale + MINOR_BORDER_SIZE;
}
static inline int
-day_height( GncDenseCal *dcal )
+day_height(GncDenseCal *dcal)
{
- return day_height_at( dcal, dcal->y_scale );
+ return day_height_at(dcal, dcal->y_scale);
}
static inline int
-week_width_at( GncDenseCal *dcal, guint xScale )
+week_width_at(GncDenseCal *dcal, guint xScale)
{
- return day_width_at(dcal, xScale) * 7;
+ return day_width_at(dcal, xScale) * 7;
}
static inline int
-week_width( GncDenseCal *dcal )
+week_width(GncDenseCal *dcal)
{
- return week_width_at( dcal, dcal->x_scale );
+ return week_width_at(dcal, dcal->x_scale);
}
static inline int
-week_height_at( GncDenseCal *dcal, guint yScale )
+week_height_at(GncDenseCal *dcal, guint yScale)
{
- return day_height_at(dcal, yScale);
+ return day_height_at(dcal, yScale);
}
static inline int
-week_height( GncDenseCal *dcal )
+week_height(GncDenseCal *dcal)
{
- return week_height_at(dcal, dcal->y_scale);
+ return week_height_at(dcal, dcal->y_scale);
}
static inline int
-col_width_at( GncDenseCal *dcal, guint xScale )
+col_width_at(GncDenseCal *dcal, guint xScale)
{
- return (week_width_at(dcal, xScale)
- + dcal->label_width
- + COL_BORDER_SIZE);
+ return (week_width_at(dcal, xScale)
+ + dcal->label_width
+ + COL_BORDER_SIZE);
}
static inline int
-col_width( GncDenseCal *dcal )
+col_width(GncDenseCal *dcal)
{
- return col_width_at( dcal, dcal->x_scale );
+ return col_width_at(dcal, dcal->x_scale);
}
static inline int
-col_height( GncDenseCal *dcal )
+col_height(GncDenseCal *dcal)
{
- return week_height(dcal)
- * num_weeks_per_col(dcal);
+ return week_height(dcal) * num_weeks_per_col(dcal);
}
static inline int
-num_cols( GncDenseCal *dcal )
+num_cols(GncDenseCal *dcal)
{
- return ceil( (float)dcal->numMonths / (float)dcal->monthsPerCol );
+ return ceil((float)dcal->numMonths / (float)dcal->monthsPerCol);
}
static inline int
-num_weeks( GncDenseCal *dcal )
+num_weeks(GncDenseCal *dcal)
{
- /* FIXME: calculate, remove 'recompute_extents' */
- return dcal->num_weeks;
+ return dcal->num_weeks;
}
static
-int num_weeks_per_col( GncDenseCal *dcal )
+int num_weeks_per_col(GncDenseCal *dcal)
{
- int num_weeks_toRet, numCols, i;
- GDate *start,*end;
- int startWeek, endWeek;
+ int num_weeks_toRet, numCols, i;
+ GDate *start,*end;
+ int startWeek, endWeek;
- start = g_date_new();
- end = g_date_new();
+ start = g_date_new();
+ end = g_date_new();
- num_weeks_toRet = 0;
- numCols = num_cols(dcal);
+ num_weeks_toRet = 0;
+ numCols = num_cols(dcal);
- for ( i=0; i<numCols; i++ ) {
- g_date_set_dmy( start, 1,
- ((dcal->month - 1 +
- (i * dcal->monthsPerCol)) % 12)
- + 1,
- dcal->year + floor((dcal->month - 1
- + (i*dcal->monthsPerCol))
- / 12) );
- *end = *start;
- /* Add the smaller of (the number of months in the
- * calendar-display, minus the number of months shown in the
- * previous columns) or (the number of months in a column) */
- g_date_add_months( end, MIN( dcal->numMonths,
- MIN( dcal->monthsPerCol,
- dcal->numMonths
- - ((i-1)
- * dcal->monthsPerCol) ) ) );
- g_date_subtract_days( end, 1 );
- startWeek = g_date_get_sunday_week_of_year( start );
- endWeek = g_date_get_sunday_week_of_year( end );
- if ( endWeek < startWeek ) {
- endWeek += g_date_get_sunday_weeks_in_year( g_date_get_year(start) );
- }
- num_weeks_toRet = MAX( num_weeks_toRet, (endWeek - startWeek)+1 );
- }
- return num_weeks_toRet;
+ for (i=0; i<numCols; i++)
+ {
+ g_date_set_dmy(start, 1,
+ ((dcal->month - 1
+ + (i * dcal->monthsPerCol)) % 12)
+ + 1,
+ dcal->year + floor((dcal->month - 1
+ + (i*dcal->monthsPerCol))
+ / 12));
+ *end = *start;
+ /* Add the smaller of (the number of months in the
+ * calendar-display, minus the number of months shown in the
+ * previous columns) or (the number of months in a column) */
+ g_date_add_months(end, MIN(dcal->numMonths,
+ MIN(dcal->monthsPerCol,
+ dcal->numMonths
+ - ((i-1)
+ * dcal->monthsPerCol))));
+ g_date_subtract_days(end, 1);
+ startWeek = g_date_get_sunday_week_of_year(start);
+ endWeek = g_date_get_sunday_week_of_year(end);
+ if (endWeek < startWeek)
+ {
+ endWeek += g_date_get_sunday_weeks_in_year(g_date_get_year(start));
+ }
+ num_weeks_toRet = MAX(num_weeks_toRet, (endWeek - startWeek)+1);
+ }
+ return num_weeks_toRet;
}
/**
@@ -1261,167 +1254,171 @@
* size of the month.
**/
static void
-month_coords( GncDenseCal *dcal, int monthOfCal, GList **outList )
+month_coords(GncDenseCal *dcal, int monthOfCal, GList **outList)
{
- gint weekRow, colNum, previousMonthsInCol, monthOffset;
- gint start;
- GDate *startD, *endD;
- GdkRectangle *rect;
- gint startWk, endWk;
+ gint weekRow, colNum, previousMonthsInCol, monthOffset;
+ gint start;
+ GDate *startD, *endD;
+ GdkRectangle *rect;
+ gint startWk, endWk;
- if ( monthOfCal > dcal->numMonths ) {
- return;
- }
- colNum = floor(monthOfCal / dcal->monthsPerCol);
- monthOffset = colNum * dcal->monthsPerCol;
- previousMonthsInCol = MAX( 0, (monthOfCal % dcal->monthsPerCol) );
+ if (monthOfCal > dcal->numMonths)
+ return;
- startD = g_date_new();
- endD = g_date_new();
- // FIXME: clean these up?
+ colNum = floor(monthOfCal / dcal->monthsPerCol);
+ monthOffset = colNum * dcal->monthsPerCol;
+ previousMonthsInCol = MAX(0, (monthOfCal % dcal->monthsPerCol));
- /* Calculate the number of weeks in the column before the month we're
- * interested in. */
- weekRow = 0;
- if ( previousMonthsInCol > 0 ) {
- g_date_set_dmy( startD, 1,
- ((dcal->month - 1 + monthOffset) % 12) + 1,
- dcal->year + floor((dcal->month-1+monthOffset)/12) );
- /* get the week of the top of the column */
- startWk = g_date_get_sunday_week_of_year( startD );
- /* get the week of the end of the previous months */
- *endD = *startD;
- g_date_add_months( endD, previousMonthsInCol );
- g_date_subtract_days( endD, 1 );
- endWk = g_date_get_sunday_week_of_year( endD );
- if ( endWk < startWk ) {
- endWk += g_date_get_sunday_weeks_in_year( g_date_get_year(startD) );
- }
- /* determine how many weeks are before the month we're
- * interested in. */
- weekRow = endWk - startWk;
- if ( g_date_get_weekday(endD) == G_DATE_SATURDAY ) {
- weekRow++;
- }
- }
+ startD = g_date_new();
+ endD = g_date_new();
+ // FIXME: clean these up?
- g_date_set_dmy( startD, 1,
- ((dcal->month - 1 + monthOfCal) % 12) + 1,
- dcal->year + floor((dcal->month-1+monthOfCal)/12) );
- *endD = *startD;
- g_date_add_months( endD, 1 );
- g_date_subtract_days( endD, 1 );
- /* Get the first week. */
- {
- start = g_date_get_weekday( startD ) % 7;
- rect = g_new0( GdkRectangle, 1 );
- rect->x = dcal->leftPadding
- + MINOR_BORDER_SIZE
- + (colNum * (col_width(dcal) + COL_BORDER_SIZE))
- + dcal->label_width
- + (start * day_width(dcal));
- rect->y = dcal->topPadding
- + dcal->dayLabelHeight
- + MINOR_BORDER_SIZE
- + (weekRow * week_height(dcal) );
- rect->width = (7 - start) * day_width(dcal);
- rect->height = week_height(dcal);
- *outList = g_list_append(*outList, (gpointer)rect );
- rect = NULL;
- }
+ /* Calculate the number of weeks in the column before the month we're
+ * interested in. */
+ weekRow = 0;
+ if (previousMonthsInCol > 0)
+ {
+ g_date_set_dmy(startD, 1,
+ ((dcal->month - 1 + monthOffset) % 12) + 1,
+ dcal->year + floor((dcal->month-1+monthOffset)/12));
+ /* get the week of the top of the column */
+ startWk = g_date_get_sunday_week_of_year(startD);
+ /* get the week of the end of the previous months */
+ *endD = *startD;
+ g_date_add_months(endD, previousMonthsInCol);
+ g_date_subtract_days(endD, 1);
+ endWk = g_date_get_sunday_week_of_year(endD);
+ if (endWk < startWk)
+ {
+ endWk += g_date_get_sunday_weeks_in_year(g_date_get_year(startD));
+ }
+ /* determine how many weeks are before the month we're
+ * interested in. */
+ weekRow = endWk - startWk;
+ if (g_date_get_weekday(endD) == G_DATE_SATURDAY)
+ {
+ weekRow++;
+ }
+ }
- /* Get the middle weeks. */
- {
- gint i, weekStart, weekEnd;
+ g_date_set_dmy(startD, 1,
+ ((dcal->month - 1 + monthOfCal) % 12) + 1,
+ dcal->year + floor((dcal->month-1+monthOfCal)/12));
+ *endD = *startD;
+ g_date_add_months(endD, 1);
+ g_date_subtract_days(endD, 1);
+ /* Get the first week. */
+ {
+ start = g_date_get_weekday(startD) % 7;
+ rect = g_new0(GdkRectangle, 1);
+ rect->x = dcal->leftPadding
+ + MINOR_BORDER_SIZE
+ + (colNum * (col_width(dcal) + COL_BORDER_SIZE))
+ + dcal->label_width
+ + (start * day_width(dcal));
+ rect->y = dcal->topPadding
+ + dcal->dayLabelHeight
+ + MINOR_BORDER_SIZE
+ + (weekRow * week_height(dcal));
+ rect->width = (7 - start) * day_width(dcal);
+ rect->height = week_height(dcal);
+ *outList = g_list_append(*outList, (gpointer)rect);
+ rect = NULL;
+ }
- weekStart = g_date_get_sunday_week_of_year(startD)+1;
- weekEnd = g_date_get_sunday_week_of_year(endD);
- for ( i=weekStart; i<weekEnd; i++ ) {
- rect = g_new0( GdkRectangle, 1 );
- rect->x = dcal->leftPadding
- + MINOR_BORDER_SIZE
- + dcal->label_width
- + (colNum * (col_width(dcal) + COL_BORDER_SIZE));
- rect->y = dcal->topPadding
- + dcal->dayLabelHeight
- + MINOR_BORDER_SIZE
- + ((weekRow + (i-weekStart) + 1) * week_height(dcal));
- rect->width = week_width(dcal);
- rect->height = week_height(dcal);
+ /* Get the middle weeks. */
+ {
+ gint i, weekStart, weekEnd;
- *outList = g_list_append( *outList, (gpointer)rect );
- rect = NULL;
- }
- }
+ weekStart = g_date_get_sunday_week_of_year(startD)+1;
+ weekEnd = g_date_get_sunday_week_of_year(endD);
+ for (i=weekStart; i<weekEnd; i++) {
+ rect = g_new0(GdkRectangle, 1);
+ rect->x = dcal->leftPadding
+ + MINOR_BORDER_SIZE
+ + dcal->label_width
+ + (colNum * (col_width(dcal) + COL_BORDER_SIZE));
+ rect->y = dcal->topPadding
+ + dcal->dayLabelHeight
+ + MINOR_BORDER_SIZE
+ + ((weekRow + (i-weekStart) + 1) * week_height(dcal));
+ rect->width = week_width(dcal);
+ rect->height = week_height(dcal);
+
+ *outList = g_list_append(*outList, (gpointer)rect);
+ rect = NULL;
+ }
+ }
- /* Get the last week. */
- {
- rect = g_new0( GdkRectangle, 1 );
- rect->x = dcal->leftPadding
- + MINOR_BORDER_SIZE
- + dcal->label_width
- + (colNum * (col_width(dcal) + COL_BORDER_SIZE));
- rect->y = dcal->topPadding
- + MINOR_BORDER_SIZE
- + dcal->dayLabelHeight
- + ((weekRow
- + (g_date_get_sunday_week_of_year(endD)
- - g_date_get_sunday_week_of_year(startD)))
- * week_height(dcal));
- rect->width = ((g_date_get_weekday(endD) % 7)+1) * day_width(dcal);
- rect->height = week_height(dcal);
+ /* Get the last week. */
+ {
+ rect = g_new0(GdkRectangle, 1);
+ rect->x = dcal->leftPadding
+ + MINOR_BORDER_SIZE
+ + dcal->label_width
+ + (colNum * (col_width(dcal) + COL_BORDER_SIZE));
+ rect->y = dcal->topPadding
+ + MINOR_BORDER_SIZE
+ + dcal->dayLabelHeight
+ + ((weekRow
+ + (g_date_get_sunday_week_of_year(endD)
+ - g_date_get_sunday_week_of_year(startD)))
+ * week_height(dcal));
+ rect->width = ((g_date_get_weekday(endD) % 7)+1) * day_width(dcal);
+ rect->height = week_height(dcal);
- *outList = g_list_append( *outList, (gpointer)rect );
- rect = NULL;
- }
+ *outList = g_list_append(*outList, (gpointer)rect);
+ rect = NULL;
+ }
}
/* FIXME: make this more like month_coords */
static void
-doc_coords( GncDenseCal *dcal, int dayOfCal,
- int *x1, int *y1, int *x2, int *y2 )
+doc_coords(GncDenseCal *dcal, int dayOfCal,
+ int *x1, int *y1, int *x2, int *y2)
{
- GDate d;
- gint docMonth;
- gint d_week_of_cal, top_of_col_week_of_cal;
- gint colNum, dayCol, weekRow;
+ GDate d;
+ gint docMonth;
+ gint d_week_of_cal, top_of_col_week_of_cal;
+ gint colNum, dayCol, weekRow;
- /* FIXME: add range checks */
- g_date_set_dmy( &d, 1, dcal->month, dcal->year );
- g_date_add_days( &d, dayOfCal );
- docMonth = g_date_get_month( &d );
- if ( g_date_get_year( &d ) != dcal->year ) {
- docMonth += 12;
- }
- colNum = floor( (float)(docMonth - dcal->month) / (float)dcal->monthsPerCol );
- dayCol = g_date_get_weekday( &d ) % 7;
- d_week_of_cal = g_date_get_sunday_week_of_year( &d );
- g_date_set_dmy( &d, 1, dcal->month, dcal->year );
- g_date_add_months( &d, (colNum * dcal->monthsPerCol) );
- top_of_col_week_of_cal = g_date_get_sunday_week_of_year( &d );
- if ( d_week_of_cal < top_of_col_week_of_cal ) {
- d_week_of_cal +=
- g_date_get_sunday_weeks_in_year( dcal->year );
- }
- weekRow = d_week_of_cal - top_of_col_week_of_cal;
+ /* FIXME: add range checks */
+ g_date_set_dmy(&d, 1, dcal->month, dcal->year);
+ g_date_add_days(&d, dayOfCal);
+ docMonth = g_date_get_month(&d);
+ if (g_date_get_year(&d) != dcal->year)
+ {
+ docMonth += 12;
+ }
+ colNum = floor((float)(docMonth - dcal->month) / (float)dcal->monthsPerCol);
+ dayCol = g_date_get_weekday(&d) % 7;
+ d_week_of_cal = g_date_get_sunday_week_of_year(&d);
+ g_date_set_dmy(&d, 1, dcal->month, dcal->year);
+ g_date_add_months(&d, (colNum * dcal->monthsPerCol));
+ top_of_col_week_of_cal = g_date_get_sunday_week_of_year(&d);
+ if (d_week_of_cal < top_of_col_week_of_cal)
+ {
+ d_week_of_cal += g_date_get_sunday_weeks_in_year(dcal->year);
+ }
+ weekRow = d_week_of_cal - top_of_col_week_of_cal;
- /* top-left corner */
- /* FIXME: this has the math to make the mark-cells come out right,
- * which it shouldn't. */
- *x1 = dcal->leftPadding
- + MINOR_BORDER_SIZE
- + dcal->label_width
- + (colNum * (col_width(dcal) + COL_BORDER_SIZE))
- + (dayCol * day_width(dcal))
- + (day_width(dcal)/4);
- *y1 = dcal->topPadding
- + MINOR_BORDER_SIZE
- + dcal->dayLabelHeight
- + (weekRow * week_height(dcal))
- + (day_height(dcal)/4);
+ /* top-left corner */
+ /* FIXME: this has the math to make the mark-cells come out right,
+ * which it shouldn't. */
+ *x1 = dcal->leftPadding
+ + MINOR_BORDER_SIZE
+ + dcal->label_width
+ + (colNum * (col_width(dcal) + COL_BORDER_SIZE))
+ + (dayCol * day_width(dcal))
+ + (day_width(dcal)/4);
+ *y1 = dcal->topPadding
+ + MINOR_BORDER_SIZE
+ + dcal->dayLabelHeight
+ + (weekRow * week_height(dcal))
+ + (day_height(dcal)/4);
- *x2 = *x1 + (day_width(dcal)/2);
- *y2 = *y1 + (day_height(dcal)/2);
+ *x2 = *x1 + (day_width(dcal)/2);
+ *y2 = *y1 + (day_height(dcal)/2);
}
/**
@@ -1429,211 +1426,325 @@
* '-1' if invalid.
**/
static gint
-wheres_this( GncDenseCal *dcal, int x, int y )
+wheres_this(GncDenseCal *dcal, int x, int y)
{
- gint colNum, weekRow, dayCol, dayOfCal;
- GDate d, startD;
+ gint colNum, weekRow, dayCol, dayOfCal;
+ GDate d, startD;
- x -= dcal->leftPadding;
- y -= dcal->topPadding;
+ x -= dcal->leftPadding;
+ y -= dcal->topPadding;
- if ( (x < 0) || (y < 0) ) {
- /* DEBUG( "x(%d) or y(%d) < 0", x, y ); */
- return -1;
- }
- if ( (x >= GTK_WIDGET(dcal)->allocation.width)
- || (y >= GTK_WIDGET(dcal)->allocation.height) ) {
- /*DEBUG( "x(%d) > allocation.width(%d) or y(%d) > allocation->height(%d)",
- x, y,
- GTK_WIDGET(dcal)->allocation.width,
- GTK_WIDGET(dcal)->allocation.height );*/
- return -1;
- }
+ if ((x < 0) || (y < 0))
+ {
+ /* DEBUG("x(%d) or y(%d) < 0", x, y); */
+ return -1;
+ }
+ if ((x >= GTK_WIDGET(dcal)->allocation.width)
+ || (y >= GTK_WIDGET(dcal)->allocation.height))
+ {
+ /*DEBUG("x(%d) > allocation.width(%d) or y(%d) > allocation->height(%d)",
+ x, y,
+ GTK_WIDGET(dcal)->allocation.width,
+ GTK_WIDGET(dcal)->allocation.height);*/
+ return -1;
+ }
- /* "outside of displayed table" check */
- if ( x >= (num_cols(dcal) * (col_width(dcal) + COL_BORDER_SIZE)) ) {
- /*DEBUG( "x(%d) > ( col_width(%d) * num_cols(%d) )",
- x, col_width(dcal), num_cols(dcal) );*/
- return -1;
- }
- if ( y >= col_height(dcal) ) {
- /*DEBUG( "y(%d) > col_height(%d)",
- y, col_height(dcal) );*/
- return -1;
- }
+ /* "outside of displayed table" check */
+ if (x >= (num_cols(dcal) * (col_width(dcal) + COL_BORDER_SIZE)))
+ {
+ /*DEBUG("x(%d) > (col_width(%d) * num_cols(%d))",
+ x, col_width(dcal), num_cols(dcal));*/
+ return -1;
+ }
+ if (y >= col_height(dcal))
+ {
+ /*DEBUG("y(%d) > col_height(%d)",
+ y, col_height(dcal));*/
+ return -1;
+ }
- /* coords -> year-relative-values */
- colNum = floor( x / (col_width(dcal)+COL_BORDER_SIZE) );
+ /* coords -> year-relative-values */
+ colNum = floor(x / (col_width(dcal)+COL_BORDER_SIZE));
+
+ x %= (col_width(dcal)+COL_BORDER_SIZE);
+ x -= dcal->label_width;
+ if (x < 0)
+ {
+ /* DEBUG("X is over the label.");*/
+ return -1;
+ }
+ if (x >= day_width(dcal) * 7)
+ {
+ /*DEBUG("X is in the col_border space.");*/
+ return -1;
+ }
- x %= (col_width(dcal)+COL_BORDER_SIZE);
- x -= dcal->label_width;
- if ( x < 0 ) {
- /* DEBUG( "X is over the label." );*/
- return -1;
- }
- if ( x >= day_width(dcal) * 7 ) {
- /*DEBUG( "X is in the col_border space." );*/
- return -1;
- }
+ y -= dcal->dayLabelHeight;
+ if (y < 0)
+ {
+ /*DEBUG("Y is over the label.");*/
+ return -1;
+ }
- y -= dcal->dayLabelHeight;
- if ( y < 0 ) {
- /*DEBUG( "Y is over the label." );*/
- return -1;
- }
+ dayCol = floor((float)x / (float)day_width(dcal));
+ weekRow = floor((float)y / (float)week_height(dcal));
- dayCol = floor( (float)x / (float)day_width(dcal) );
- weekRow = floor( (float)y / (float)week_height(dcal) );
+ g_date_set_dmy(&startD, 1, dcal->month, dcal->year);
+ d = startD;
+ g_date_add_months(&d, (colNum * dcal->monthsPerCol));
+ dayCol -= (g_date_get_weekday(&d) % 7);
+ if (weekRow == 0)
+ {
+ if (dayCol < 0)
+ {
+ /*DEBUG("Before the beginning of the first month.");*/
+ return -1;
+ }
+ }
+ g_date_add_days(&d, dayCol + (weekRow * 7));
- g_date_set_dmy( &startD, 1, dcal->month, dcal->year );
- d = startD;
- g_date_add_months( &d, (colNum * dcal->monthsPerCol) );
- dayCol -= (g_date_get_weekday(&d) % 7);
- if ( weekRow == 0 ) {
- if ( dayCol < 0 ) {
- /*DEBUG( "Before the beginning of the first month." );*/
- return -1;
- }
- }
- g_date_add_days( &d, dayCol + (weekRow * 7) );
+ /* Check to make sure we're within the column's displayed range. */
+ {
+ GDate ccd;
+ g_date_set_dmy(&ccd, 1, dcal->month, dcal->year);
+ g_date_add_months(&ccd, (colNum+1) * dcal->monthsPerCol);
+ if (g_date_get_julian(&d) >= g_date_get_julian(&ccd))
+ {
+ /*DEBUG("%d outside of column range [%d]",
+ g_date_get_julian(&d), g_date_get_julian(&ccd));*/
+ return -1;
+ }
+ }
- /* Check to make sure we're within the column's displayed range. */
- {
- GDate ccd;
- g_date_set_dmy( &ccd, 1, dcal->month, dcal->year );
- g_date_add_months( &ccd, (colNum+1) * dcal->monthsPerCol );
- if ( g_date_get_julian(&d) >= g_date_get_julian(&ccd) ) {
- /*DEBUG( "%d outside of column range [%d]",
- g_date_get_julian(&d), g_date_get_julian(&ccd) );*/
- return -1;
- }
- }
+ dayOfCal = g_date_get_julian(&d) - g_date_get_julian(&startD);
- dayOfCal = g_date_get_julian(&d) - g_date_get_julian(&startD);
+ /* one more check before returning... */
+ g_date_subtract_months(&d, dcal->numMonths);
+ if (g_date_get_julian(&d) >= g_date_get_julian(&startD))
+ {
+ /* we're past the end of the displayed calendar, thus -1 */
+ DEBUG("%d >= %d", g_date_get_julian(&d), g_date_get_julian(&startD));
+ return -1;
+ }
- /* one more check before returning... */
- g_date_subtract_months( &d, dcal->numMonths );
- if ( g_date_get_julian(&d) >= g_date_get_julian(&startD) ) {
- /* we're past the end of the displayed calendar, thus -1 */
- DEBUG( "%d >= %d",
- g_date_get_julian( &d ), g_date_get_julian( &startD ) );
- return -1;
- }
-
- return dayOfCal;
+ return dayOfCal;
}
static gint
-gdc_get_doc_offset( GncDenseCal *dcal, GDate *d )
+gdc_get_doc_offset(GncDenseCal *dcal, GDate *d)
{
- gint toRet;
- /* soc == start-of-calendar */
- GDate soc;
+ gint toRet;
+ /* soc == start-of-calendar */
+ GDate soc;
- g_date_set_dmy( &soc, 1, dcal->month, dcal->year );
- /* ensure not before calendar start. */
- if ( g_date_get_julian(d) < g_date_get_julian(&soc) ) {
- return -1;
- }
- /* do computation here, since we're going to change the
- * start-of-calendar date. */
- toRet = g_date_get_julian(d) - g_date_get_julian(&soc);
- /* ensure not after end of visible calendar. */
- g_date_add_months( &soc, dcal->numMonths );
- if ( g_date_get_julian(d) > g_date_get_julian(&soc) ) {
- return -1;
- }
- /* return pre-computed value. */
- return toRet;
+ g_date_clear(&soc, 1);
+ g_date_set_dmy(&soc, 1, dcal->month, dcal->year);
+ /* ensure not before calendar start. */
+ if (g_date_get_julian(d) < g_date_get_julian(&soc))
+ return -1;
+ /* do computation here, since we're going to change the
+ * start-of-calendar date. */
+ toRet = g_date_get_julian(d) - g_date_get_julian(&soc);
+ /* ensure not after end of visible calendar. */
+ g_date_add_months(&soc, dcal->numMonths);
+ if (g_date_get_julian(d) > g_date_get_julian(&soc))
+ return -1;
+ /* return pre-computed value. */
+ return toRet;
}
+static void
+gdc_add_tag_markings(GncDenseCal *cal, guint tag)
+{
+ gchar *name, *info;
+ gint num_marks, idx;
+ GDate **dates;
+
+ // copy the values into the old marking function.
+ name = gnc_dense_cal_model_get_name(cal->model, tag);
+ info = gnc_dense_cal_model_get_info(cal->model, tag);
+ num_marks = gnc_dense_cal_model_get_instance_count(cal->model, tag);
+
+ if (num_marks == 0)
+ return;
+
+ dates = g_new0(GDate*, num_marks);
+ for (idx = 0; idx < num_marks; idx++)
+ {
+ dates[idx] = g_date_new();
+ gnc_dense_cal_model_get_instance(cal->model, tag, idx, dates[idx]);
+ }
+
+ gdc_mark_add(cal, tag, name, info, num_marks, dates);
+
+ for (idx = 0; idx < num_marks; idx++)
+ {
+ g_date_free(dates[idx]);
+ }
+ g_free(dates);
+}
+
+static void
+gdc_add_markings(GncDenseCal *cal)
+{
+ GList *tags;
+ tags = gnc_dense_cal_model_get_contained(cal->model);
+ for (; tags != NULL; tags = tags->next)
+ {
+ guint tag = GPOINTER_TO_UINT(tags->data);
+ gdc_add_tag_markings(cal, tag);
+ }
+}
+
+static void
+gdc_remove_markings(GncDenseCal *cal)
+{
+ GList *tags;
+ tags = gnc_dense_cal_model_get_contained(cal->model);
+ for (; tags != NULL; tags = tags->next)
+ {
+ guint tag = GPOINTER_TO_UINT(tags->data);
+ gdc_mark_remove(cal, tag);
+ }
+}
+
+static void
+gdc_model_added_cb(GncDenseCalModel *model, guint added_tag, gpointer user_data)
+{
+ GncDenseCal *cal = GNC_DENSE_CAL(user_data);
+ printf("gdc_model_added_cb update\n");
+ gdc_add_tag_markings(cal, added_tag);
+}
+
+static void
+gdc_model_update_cb(GncDenseCalModel *model, guint update_tag, gpointer user_data)
+{
+ GncDenseCal *cal = GNC_DENSE_CAL(user_data);
+ printf("gdc_model_update_cb update for tag [%d]\n", update_tag);
+ gdc_mark_remove(cal, update_tag);
+ gdc_add_tag_markings(cal, update_tag);
+}
+
+static void
+gdc_model_removing_cb(GncDenseCalModel *model, guint remove_tag, gpointer user_data)
+{
+ GncDenseCal *cal = GNC_DENSE_CAL(user_data);
+ printf("gdc_model_removing_cb update [%d]\n", remove_tag);
+ gdc_mark_remove(cal, remove_tag);
+}
+
+void
+gnc_dense_cal_set_model(GncDenseCal *cal, GncDenseCalModel *model)
+{
+ if (cal->model != NULL)
+ {
+ gdc_remove_markings(cal);
+ g_object_unref(G_OBJECT(cal->model));
+ cal->model = NULL;
+ }
+ cal->model = model;
+ g_object_ref(G_OBJECT(model));
+ g_signal_connect(G_OBJECT(cal->model), "added", (GCallback)gdc_model_added_cb, cal);
+ g_signal_connect(G_OBJECT(cal->model), "update", (GCallback)gdc_model_update_cb, cal);
+ g_signal_connect(G_OBJECT(cal->model), "removing", (GCallback)gdc_model_removing_cb, cal);
+
+ gdc_add_markings(cal);
+}
+
/**
* Marks the given array of GDate*s on the calendar with the given name.
**/
-guint
-gnc_dense_cal_mark( GncDenseCal *dcal,
- guint size, GDate **dateArray,
- gchar *name, gchar *info )
+static void
+gdc_mark_add(GncDenseCal *dcal,
+ guint tag,
+ gchar *name,
+ gchar *info,
+ guint size,
+ GDate **dateArray)
{
- guint i;
- gint doc;
- gdc_mark_data *newMark;
- GDate *d;
+ guint i;
+ gint doc;
+ gdc_mark_data *newMark;
+ GDate *d;
- if ( size == 0 ) {
- PERR( "0 size not allowed\n" );
- return -1;
- }
+ if (size == 0)
+ {
+ PERR("0 size not allowed\n");
+ return;
+ }
- newMark = g_new0( gdc_mark_data, 1 );
- newMark->name = NULL;
- if ( name ) {
- newMark->name = g_strdup(name);
- }
- newMark->info = NULL;
- if ( info ) {
- newMark->info = g_strdup(info);
- }
- newMark->tag = dcal->lastMarkTag++;
- newMark->ourMarks = NULL;
+ newMark = g_new0(gdc_mark_data, 1);
+ newMark->name = NULL;
+ if (name)
+ newMark->name = g_strdup(name);
+ newMark->info = NULL;
+ if (info)
+ newMark->info = g_strdup(info);
+ newMark->tag = tag;
+ newMark->ourMarks = NULL;
+ printf("saving mark with tag [%d]\n", newMark->tag);
- for ( i=0; i<size; i++ ) {
- d = dateArray[i];
- doc = gdc_get_doc_offset( dcal, d );
- if ( doc < 0 ) {
- continue;
- }
- if ( doc >= dcal->numMarks ) {
- /* It's not going to get any better, so just
- * stop processing. */
- break;
- }
- dcal->marks[doc] = g_list_append( dcal->marks[doc], newMark );
- newMark->ourMarks = g_list_append( newMark->ourMarks,
- GINT_TO_POINTER(doc) );
- }
- dcal->markData = g_list_append( dcal->markData, (gpointer)newMark );
- gnc_dense_cal_draw_to_buffer( dcal );
- gtk_widget_queue_draw( GTK_WIDGET( dcal ) );
- return newMark->tag;
+ for (i=0; i<size; i++)
+ {
+ d = dateArray[i];
+ doc = gdc_get_doc_offset(dcal, d);
+ if (doc < 0)
+ continue;
+ if (doc >= dcal->numMarks)
+ {
+ /* It's not going to get any better, so just
+ * stop processing. */
+ break;
+ }
+ dcal->marks[doc] = g_list_append(dcal->marks[doc], newMark);
+ newMark->ourMarks = g_list_append(newMark->ourMarks,
+ GINT_TO_POINTER(doc));
+ }
+ dcal->markData = g_list_append(dcal->markData, (gpointer)newMark);
+ gnc_dense_cal_draw_to_buffer(dcal);
+ gtk_widget_queue_draw(GTK_WIDGET(dcal));
}
-void
-gnc_dense_cal_mark_remove( GncDenseCal *dcal, guint markToRemove )
+static void
+gdc_mark_remove(GncDenseCal *dcal, guint mark_to_remove)
{
- GList *l, *calMarkL;
- gint doc;
- gdc_mark_data *gdcmd;
+ GList *iter, *calendar_marks;
+ gint day_of_cal;
+ gdc_mark_data *mark_data;
- /* Ignore non-realistic marks */
- if ( (gint)markToRemove == -1 ) {
- DEBUG( "markToRemove = -1" );
- return;
- }
+ /* Ignore non-realistic marks */
+ if ((gint)mark_to_remove == -1)
+ {
+ DEBUG("mark_to_remove = -1");
+ return;
+ }
- gdcmd = NULL;
- for ( l = dcal->markData; l; l=l->next ) {
- gdcmd = (gdc_mark_data*)l->data;
- if ( gdcmd->tag == markToRemove )
- break;
- }
- g_assert( l != NULL );
- if ( l == NULL ) {
- DEBUG( "l == null" );
- return;
- }
- g_assert( gdcmd != NULL );
+ mark_data = NULL;
+ for (iter = dcal->markData; iter != NULL; iter = iter->next)
+ {
+ mark_data = (gdc_mark_data*)iter->data;
+ if (mark_data->tag == mark_to_remove)
+ break;
+ }
+ if (iter == NULL)
+ {
+ DEBUG("couldn't find tag [%d]", mark_to_remove);
+ return;
+ }
+ if (mark_data == NULL)
+ {
+ DEBUG("mark_data == null");
+ return;
+ }
- l = NULL;
- for ( calMarkL = gdcmd->ourMarks;
- calMarkL;
- calMarkL = calMarkL->next ) {
- doc = GPOINTER_TO_INT(calMarkL->data);
- dcal->marks[doc] = g_list_remove( dcal->marks[doc], gdcmd );
- }
- g_list_free( gdcmd->ourMarks );
- dcal->markData = g_list_remove( dcal->markData, gdcmd );
- g_free( gdcmd );
- gnc_dense_cal_draw_to_buffer( dcal );
- gtk_widget_queue_draw( GTK_WIDGET(dcal) );
+ for (calendar_marks = mark_data->ourMarks; calendar_marks != NULL; calendar_marks = calendar_marks->next)
+ {
+ day_of_cal = GPOINTER_TO_INT(calendar_marks->data);
+ dcal->marks[day_of_cal] = g_list_remove(dcal->marks[day_of_cal], mark_data);
+ }
+ g_list_free(mark_data->ourMarks);
+ dcal->markData = g_list_remove(dcal->markData, mark_data);
+ g_free(mark_data);
+ gnc_dense_cal_draw_to_buffer(dcal);
+ gtk_widget_queue_draw(GTK_WIDGET(dcal));
}
Modified: gnucash/trunk/src/gnome-utils/gnc-dense-cal.h
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-dense-cal.h 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome-utils/gnc-dense-cal.h 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,14 +1,11 @@
-#ifndef _DENSECAL_H_
-#define _DENSECAL_H_
-
/********************************************************************\
* gnc-dense-cal.h : a custom densely-dispalyed calendar widget *
- * Copyright (C) 2002 Joshua Sled <jsled at asynchronous.org> *
+ * Copyright (C) 2002,2006 Joshua Sled <jsled at asynchronous.org> *
* *
* 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. *
+ * published by the Free Software Foundation, under version 2 of *
+ * the License. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
@@ -23,14 +20,17 @@
* Boston, MA 02110-1301, USA gnu at gnu.org *
\********************************************************************/
-#include <gdk/gdk.h>
-#include <gtk/gtkadjustment.h>
-#include <gtk/gtkwidget.h>
+#ifndef _GNC_DENSE_CAL_H
+#define _GNC_DENSE_CAL_H
+
+#include "config.h"
+
+#include <FreqSpec.h>
#include <glib.h>
+#include "gnc-dense-cal-model.h"
+#include <gtk/gtk.h>
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+G_BEGIN_DECLS
#define GNC_TYPE_DENSE_CAL (gnc_dense_cal_get_type ())
#define GNC_DENSE_CAL(obj) GTK_CHECK_CAST (obj, gnc_dense_cal_get_type (), GncDenseCal)
@@ -40,92 +40,97 @@
typedef struct _GncDenseCal GncDenseCal;
typedef struct _GncDenseCalClass GncDenseCalClass;
-typedef struct _gdc_month_coords {
- gint x, y;
+typedef struct _gdc_month_coords
+{
+ gint x, y;
} gdc_month_coords;
-enum GDC_COLORS {
- MONTH_THIS = 0,
- MONTH_THAT,
- MAX_COLORS
+enum GDC_COLORS
+{
+ MONTH_THIS = 0,
+ MONTH_THAT,
+ MAX_COLORS
};
struct _GncDenseCal
{
- GtkWidget widget;
+ GtkWidget widget;
- GdkPixmap *drawbuf;
+ GdkPixmap *drawbuf;
- gboolean initialized;
+ gboolean initialized;
- gboolean showPopup;
- GtkWindow *transPopup;
+ gboolean showPopup;
+ GtkWindow *transPopup;
- gint min_x_scale;
- gint min_y_scale;
+ gint min_x_scale;
+ gint min_y_scale;
- gint x_scale;
- gint y_scale;
+ gint x_scale;
+ gint y_scale;
- gint numMonths;
- gint monthsPerCol;
- gint num_weeks; /* computed */
+ gint numMonths;
+ gint monthsPerCol;
+ gint num_weeks; /* computed */
- GDateMonth month;
- gint year;
- gint firstOfMonthOffset;
+ GDateMonth month;
+ gint year;
+ gint firstOfMonthOffset;
- gint leftPadding;
- gint topPadding;
+ gint leftPadding;
+ gint topPadding;
- gboolean needInitMonthLabels;
- gdc_month_coords monthPositions[12];
- GdkFont *monthLabelFont;
- GdkFont *dayLabelFont;
- GdkPixmap *monthLabels[12];
+ gboolean needInitMonthLabels;
+ gdc_month_coords monthPositions[12];
+ GdkFont *monthLabelFont;
+ GdkFont *dayLabelFont;
+ GdkPixmap *monthLabels[12];
- GdkColor weekColors[MAX_COLORS];
+ GdkColor weekColors[MAX_COLORS];
- guint label_lbearing;
- guint label_ascent;
- guint label_width;
- guint label_height;
- guint dayLabelHeight;
+ guint label_lbearing;
+ guint label_ascent;
+ guint label_width;
+ guint label_height;
+ guint dayLabelHeight;
- guint lastMarkTag;
+ GncDenseCalModel *model;
- /**
- * A GList of gdc_mark_data structs, one for each active/valid markTag.
- **/
- GList *markData;
- int numMarks;
- /* array of GList*s of per-cell markings. */
- GList **marks;
+ guint lastMarkTag;
- int disposed; /* private */
+ /**
+ * A GList of gdc_mark_data structs, one for each active/valid markTag.
+ **/
+ GList *markData;
+ int numMarks;
+ /* array of GList*s of per-cell markings. */
+ GList **marks;
+
+ int disposed; /* private */
};
struct _GncDenseCalClass
{
- GtkWidgetClass parent_class;
- void (*marks_lost_cb)( GncDenseCal *dcal, gpointer user_data );
+ GtkWidgetClass parent_class;
};
-typedef struct _gdc_mark_data {
- gchar *name;
- gchar *info;
- guint tag;
- /* GdkColor markStyle; */
- /**
- * A GList of the dcal->marks indexes containing this mark.
- **/
- GList *ourMarks;
+typedef struct _gdc_mark_data
+{
+ gchar *name;
+ gchar *info;
+ guint tag;
+ /**
+ * A GList of the dcal->marks indexes containing this mark.
+ **/
+ GList *ourMarks;
} gdc_mark_data;
GtkWidget* gnc_dense_cal_new (void);
+GtkWidget* gnc_dense_cal_new_with_model (GncDenseCalModel *model);
GType gnc_dense_cal_get_type (void);
-void gnc_dense_cal_set_month( GncDenseCal *dcal, GDateMonth mon );
+void gnc_dense_cal_set_model(GncDenseCal *cal, GncDenseCalModel *model);
+void gnc_dense_cal_set_month(GncDenseCal *dcal, GDateMonth mon);
/**
* @param year Julian year: 2000 = 2000AD.
**/
@@ -137,13 +142,6 @@
GDateMonth gnc_dense_cal_get_month( GncDenseCal *dcal );
GDateYear gnc_dense_cal_get_year( GncDenseCal *dcal );
-guint gnc_dense_cal_mark( GncDenseCal *dcal,
- guint size, GDate **daysArray,
- gchar *name, gchar *info );
-void gnc_dense_cal_mark_remove( GncDenseCal *dcal, guint markToRemove );
+G_END_DECLS
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _DENSECAL_H_ */
+#endif /* _GNC_DENSE_CAL_H */
Modified: gnucash/trunk/src/gnome-utils/gnc-frequency.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-frequency.c 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome-utils/gnc-frequency.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -638,12 +638,12 @@
gint tmpInt;
int i;
GDate gd;
- time_t tmpTimeT;
+ time_t start_tt;
- tmpTimeT = gnc_date_edit_get_date( gf->startDate );
+ start_tt = gnc_date_edit_get_date( gf->startDate );
if ( NULL != outDate )
{
- g_date_set_time_t( outDate, tmpTimeT );
+ g_date_set_time_t( outDate, start_tt );
}
if (NULL == fs) return;
@@ -656,7 +656,7 @@
gnc_suspend_gui_refresh();
g_date_clear (&gd, 1);
- g_date_set_time_t( &gd, tmpTimeT );
+ g_date_set_time_t( &gd, start_tt );
/*uift = xaccFreqSpecGetUIType( fs );*/
uift = PAGES[page].uiFTVal;
@@ -667,6 +667,7 @@
/* hmmm... shouldn't really be allowed. */
break;
case UIFREQ_ONCE:
+ xaccFreqSpecSetOnceDate(fs, &gd);
xaccFreqSpecSetUIType( fs, uift );
break;
case UIFREQ_DAILY:
@@ -771,8 +772,8 @@
o = glade_xml_get_widget( gf->gxml, "semimonthly_second" );
day = gtk_combo_box_get_active( GTK_COMBO_BOX(o) )+1;
tmpFS = xaccFreqSpecMalloc(gnc_get_current_book ());
- tmpTimeT = gnc_date_edit_get_date( gf->startDate );
- g_date_set_time_t( &gd, tmpTimeT );
+ start_tt = gnc_date_edit_get_date( gf->startDate );
+ g_date_set_time_t( &gd, start_tt );
g_date_to_struct_tm( &gd, &stm);
if ( day >= stm.tm_mday ) {
/* next month */
@@ -788,15 +789,19 @@
}
case UIFREQ_MONTHLY:
{
- struct tm stm;
o = glade_xml_get_widget( gf->gxml, "monthly_spin" );
tmpInt = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(o));
- g_date_to_struct_tm( &gd, &stm);
o = glade_xml_get_widget( gf->gxml, "monthly_day" );
day = gtk_combo_box_get_active( GTK_COMBO_BOX(o) ) + 1;
- stm.tm_mday = day;
- g_date_set_time_t( &gd, mktime( &stm ) );
+ g_date_set_time_t(&gd, time(NULL));
+ g_date_set_month(&gd, 1);
+ g_date_set_day(&gd, day);
+ {
+ gchar buf[128];
+ g_date_strftime(buf, 127, "%c", &gd);
+ printf("monthly date [%s]\n", buf);
+ }
xaccFreqSpecSetMonthly( fs, &gd, tmpInt );
xaccFreqSpecSetUIType( fs, uift );
break;
Copied: gnucash/trunk/src/gnome-utils/gnc-sx-instance-dense-cal-adapter.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/gnc-sx-instance-dense-cal-adapter.c)
Copied: gnucash/trunk/src/gnome-utils/gnc-sx-instance-dense-cal-adapter.h (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/gnc-sx-instance-dense-cal-adapter.h)
Property changes on: gnucash/trunk/src/gnome-utils/test
___________________________________________________________________
Name: svn:ignore
- Makefile
Makefile.in
.deps
.libs
test-link-module
test-gnc-dialog
test-gnc-recurrence
semantic.cache
TAGS
*.exe
+ Makefile
Makefile.in
.deps
.libs
test-link-module
test-gnc-dialog
test-gnc-recurrence
test-sx
semantic.cache
TAGS
*.exe
Modified: gnucash/trunk/src/gnome-utils/test/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome-utils/test/Makefile.am 2007-01-19 11:49:26 UTC (rev 15398)
+++ gnucash/trunk/src/gnome-utils/test/Makefile.am 2007-01-19 23:45:45 UTC (rev 15399)
@@ -1,5 +1,5 @@
TESTS = \
- test-link-module test-load-module
+ test-link-module test-load-module test-sx
# The following tests are nice, but have absolutely no place in an
# automated testing system.
@@ -26,29 +26,30 @@
$(shell ${top_srcdir}/src/gnc-test-env --no-exports ${GNC_TEST_DEPS})
check_PROGRAMS = \
- test-link-module test-gnc-recurrence test-gnc-dialog
+ test-link-module test-gnc-recurrence test-gnc-dialog test-sx
INCLUDES= \
-I${top_srcdir}/src \
-I${top_srcdir}/src/engine \
+ -I${top_srcdir}/src/engine/test-core \
-I${top_srcdir}/src/gnome-utils \
-I${top_srcdir}/src/gnc-module \
-I${top_srcdir}/src/app-utils \
+ -I${top_srcdir}/src/test-core \
${GLIB_CFLAGS} ${GUILE_INCS} ${GNOME_CFLAGS} ${GLADE_CFLAGS} ${QOF_CFLAGS}
-test_gnc_recurrence_SOURCES=test-gnc-recurrence.c
-test_gnc_recurrence_LDADD = ${GNOME_LIBS} \
+LDADD = \
+ ${GNOME_LIBS} \
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
- ${top_builddir}/src/engine/libgncmod-engine.la
+ ${top_builddir}/src/engine/libgncmod-engine.la \
+ ${top_builddir}/src/engine/test-core/libgncmod-test-engine.la \
+ ${top_builddir}/src/test-core/libgncmod-test.la
-test_gnc_dialog_LDADD = ${GNOME_LIBS} \
- ${top_builddir}/src/app-utils/libgncmod-app-utils.la \
- ${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
- ${top_builddir}/src/engine/libgncmod-engine.la
+test_gnc_recurrence_SOURCES=test-gnc-recurrence.c
test_link_module_SOURCES=test-link-module.c
-test_link_module_LDADD= \
+test_link_module_LDADD = \
${GUILE_LIBS} \
${top_builddir}/src/gnc-module/libgnc-module.la
Copied: gnucash/trunk/src/gnome-utils/test/test-sx.c (from rev 15384, gnucash/branches/sx-cleanup/src/gnome-utils/test/test-sx.c)
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome-utils/test/test-sx.c 2007-01-15 01:57:07 UTC (rev 15384)
+++ gnucash/trunk/src/gnome-utils/test/test-sx.c 2007-01-19 23:45:45 UTC (rev 15399)
@@ -0,0 +1,82 @@
+#include "config.h"
+#include <glib.h>
+#include "qof.h"
+#include "gnc-engine.h"
+#include "gnc-sx-instance-model.h"
+#include "gnc-sx-instance-dense-cal-adapter.h"
+#include "gnc-dense-cal.h"
+#include "gnc-dense-cal-model.h"
+
+#include "test-stuff.h"
+#include "test-engine-stuff.h"
+
+static void
+_removing(GObject *obj, SchedXaction *removing, gpointer unused_user_data)
+{
+ gnc_sx_instance_model_remove_sx_instances(GNC_SX_INSTANCE_MODEL(obj), removing);
+}
+
+static void
+setup_default_handlers(GncSxInstanceModel *model)
+{
+ g_signal_connect(model, "removing", (GCallback)_removing, NULL);
+}
+
+static void
+test()
+{
+ GDate *start, *end;
+ GncSxInstanceModel *model;
+ GncSxInstanceDenseCalAdapter *dense_cal_model;
+ GncDenseCal *cal;
+ SchedXaction *foo, *bar;
+
+ start = g_date_new();
+ g_date_clear(start, 1);
+ g_date_set_time_t(start, time(NULL));
+
+ end = g_date_new();
+ g_date_clear(end, 1);
+ g_date_set_time_t(end, time(NULL));
+ g_date_add_years(end, 1);
+
+ foo = add_daily_sx("foo", start, NULL, NULL);
+
+ model = gnc_sx_get_instances(end);
+ setup_default_handlers(model);
+
+ do_test(g_list_length(model->sx_instance_list) == 1, "1 instances");
+
+ dense_cal_model = gnc_sx_instance_dense_cal_adapter_new(model);
+ cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(dense_cal_model)));
+ // gobject-2.10: g_object_ref_sink(cal);
+ g_object_ref(G_OBJECT(cal));
+ gtk_object_sink(GTK_OBJECT(cal));
+
+ bar = add_daily_sx("bar", start, NULL, NULL);
+ do_test(g_list_length(model->sx_instance_list) == 2, "2 instances");
+
+ remove_sx(foo);
+
+ do_test(g_list_length(model->sx_instance_list) == 1, "1 instance");
+
+ g_object_unref(cal);
+ success("freed calendar");
+ g_object_unref(dense_cal_model);
+ success("freed dense-cal model");
+ g_object_unref(model);
+ success("freed instances");
+}
+
+int
+main(int argc, char **argv)
+{
+ g_type_init();
+ gnc_engine_init(argc, argv);
+ gtk_init(&argc, &argv);
+
+ test();
+
+ print_test_results();
+ exit(get_rv());
+}
More information about the gnucash-changes
mailing list