r14521 - gnucash/branches/sx-cleanup - Move SX list from GList to a QofEntity; add SX list mutation events; instance-model reflects SX list mutation; move SX editor to new file.
Joshua Sled
jsled at cvs.gnucash.org
Sun Jul 16 17:35:50 EDT 2006
Author: jsled
Date: 2006-07-16 17:35:45 -0400 (Sun, 16 Jul 2006)
New Revision: 14521
Trac: http://svn.gnucash.org/trac/changeset/14521
Added:
gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.c
gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.h
Removed:
gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.c
gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.h
Modified:
gnucash/branches/sx-cleanup/ChangeLog
gnucash/branches/sx-cleanup/src/backend/file/io-gncxml-v2.c
gnucash/branches/sx-cleanup/src/doc/sx.rst
gnucash/branches/sx-cleanup/src/engine/SX-book-p.h
gnucash/branches/sx-cleanup/src/engine/SX-book.c
gnucash/branches/sx-cleanup/src/engine/SX-book.h
gnucash/branches/sx-cleanup/src/engine/gnc-engine.h
gnucash/branches/sx-cleanup/src/gnome/Makefile.am
gnucash/branches/sx-cleanup/src/gnome/dialog-sx-from-trans.c
gnucash/branches/sx-cleanup/src/gnome/dialog-sxsincelast.c
gnucash/branches/sx-cleanup/src/gnome/druid-loan.c
gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-basic-commands.c
gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.c
gnucash/branches/sx-cleanup/src/gnome/gnc-split-reg.c
gnucash/branches/sx-cleanup/src/gnome/gw-gnc-spec.scm
gnucash/branches/sx-cleanup/src/gnome/top-level.c
Log:
Move SX list from GList to a QofEntity; add SX list mutation events; instance-model reflects SX list mutation; move SX editor to new file.
* 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.
Modified: gnucash/branches/sx-cleanup/ChangeLog
===================================================================
--- gnucash/branches/sx-cleanup/ChangeLog 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/ChangeLog 2006-07-16 21:35:45 UTC (rev 14521)
@@ -1,3 +1,24 @@
+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-15 Joshua Sled <jsled at asynchronous.org>
* src/engine/SchedXaction.h (GNC_IS_SX,GNC_SX): added for convenience.
Modified: gnucash/branches/sx-cleanup/src/backend/file/io-gncxml-v2.c
===================================================================
--- gnucash/branches/sx-cleanup/src/backend/file/io-gncxml-v2.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/backend/file/io-gncxml-v2.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -246,16 +246,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
@@ -941,7 +944,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);
@@ -1076,25 +1079,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
@@ -1184,7 +1186,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/branches/sx-cleanup/src/doc/sx.rst
===================================================================
--- gnucash/branches/sx-cleanup/src/doc/sx.rst 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/doc/sx.rst 2006-07-16 21:35:45 UTC (rev 14521)
@@ -9,6 +9,8 @@
- Show Next "year"s worth of SX instances
- gnc_sx_get_instances({now + 1yr})
+- SX Editor
+
- SinceLastRun
- Last .. present (+ create-in-advance, reminder) instances
- gnc_sx_get_instances(now)
@@ -16,14 +18,17 @@
TODO
----
-- 'sx_updated' QOF events
+- [x] sx list -> qof collection
+- [ ] sx engine events
+ - [x] sx list collection add/remove -- sx-list GNC_EVENT_ITEM_ADDED, _REMOVED
+ - [ ] sx modified -- QOF_EVENT_MODIFY
- gnc_dense_cal
- change number-month properties to display (width, length)
- - set_data(GncSxUpcomingInstances *future);
- - set_model(GncSxUpcomingInstances *model);
+ - upcoming_instances_add_to_gnc_dense_cal(GncSxUpcomingInstances *future);
+ - set_model(GncTemporalInstancesModel *mdl)
+ - new interface creation.
- register callbacks for signals
- - set_data(...)
- transaction creation
- verification routine
@@ -43,12 +48,6 @@
- s/SchedXaction/Scheduled/
- s/temporal_state/instance_sequence_context/
-
-<?c
-
-
-?>
-
GtkTreeModelIface
-----------------
@@ -60,4 +59,3 @@
- rows_reordered : ???
- GtkTreeSortableIface
- -
Modified: gnucash/branches/sx-cleanup/src/engine/SX-book-p.h
===================================================================
--- gnucash/branches/sx-cleanup/src/engine/SX-book-p.h 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/engine/SX-book-p.h 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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(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/branches/sx-cleanup/src/engine/SX-book.c
===================================================================
--- gnucash/branches/sx-cleanup/src/engine/SX-book.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/engine/SX-book.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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(QofCollection *col)
{
@@ -144,78 +144,45 @@
/* ====================================================================== */
-SchedXactions *
-gnc_collection_get_schedxaction_list(QofCollection *col)
-{
- return qof_collection_get_data (col);
-}
-
-GList *
+SchedXactions*
gnc_collection_get_schedxactions(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/branches/sx-cleanup/src/engine/SX-book.h
===================================================================
--- gnucash/branches/sx-cleanup/src/engine/SX-book.h 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/engine/SX-book.h 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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(QofCollection *col);
-GList * gnc_collection_get_schedxactions(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(QofCollection *col);
+AccountGroup* gnc_book_get_template_group(QofBook* book);
+AccountGroup* gnc_collection_get_template_group(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/branches/sx-cleanup/src/engine/gnc-engine.h
===================================================================
--- gnucash/branches/sx-cleanup/src/engine/gnc-engine.h 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/engine/gnc-engine.h 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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/branches/sx-cleanup/src/gnome/Makefile.am
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/Makefile.am 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/Makefile.am 2006-07-16 21:35:45 UTC (rev 14521)
@@ -40,11 +40,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-tax-info.c \
dialog-userpass.c \
- dialog-scheduledxaction.c \
druid-acct-period.c \
druid-hierarchy.c \
druid-merge.c \
@@ -79,9 +79,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 \
druid-acct-period.h \
druid-hierarchy.h \
druid-merge.h \
Deleted: gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.h
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.h 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.h 2006-07-16 21:35:45 UTC (rev 14521)
@@ -1,65 +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);
-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 );
-
-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/branches/sx-cleanup/src/gnome/dialog-sx-editor.c (from rev 14507, gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.c)
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.c 2006-07-15 15:04:38 UTC (rev 14507)
+++ gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -0,0 +1,1795 @@
+/********************************************************************\
+ * dialog-sx-editor.c : dialog for scheduled transaction editing *
+ * 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 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 <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 "dialog-preferences.h"
+#include "dialog-sx-editor.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_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 _GncSxEditorDialog
+{
+ GladeXML *gxml;
+ GtkWidget *dialog;
+ 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 schedXact_editor_create_freq_sel( GncSxEditorDialog *sxed );
+static void schedXact_editor_create_ledger( GncSxEditorDialog *sxed );
+static void schedXact_editor_populate( GncSxEditorDialog * );
+
+static void gnc_sxed_record_size( GncSxEditorDialog *sxed );
+static void gnc_sxed_get_widgets( GncSxEditorDialog *sxed );
+static void endgroup_rb_toggled( GtkButton *b, gpointer d );
+static void set_endgroup_toggle_states( GncSxEditorDialog *sxed, EndType t );
+static void advance_toggle( GtkButton *b, GncSxEditorDialog *sxed );
+static gboolean gnc_sxed_check_consistent( GncSxEditorDialog *sxed );
+static gboolean gnc_sxed_check_changed( GncSxEditorDialog *sxed );
+static void free_keys_and_numerics_ea( gpointer key,
+ gpointer value,
+ gpointer user_data );
+static void gnc_sxed_save_sx( GncSxEditorDialog *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( GncSxEditorDialog *sxed );
+
+static void gnc_sxed_reg_check_close(GncSxEditorDialog *sxed);
+
+static gint sxed_close_event( GtkDialog *dlg, gpointer ud );
+
+static gboolean sxed_confirmed_cancel( GncSxEditorDialog *sxed );
+
+static gboolean editor_component_sx_equality( gpointer find_data,
+ 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
+sxed_close_handler ( gpointer user_data )
+{
+ GncSxEditorDialog *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. */
+}
+
+/**
+ * @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( GncSxEditorDialog *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, GncSxEditorDialog *sxed )
+{
+ /* close */
+ gnc_close_gui_component_by_data( DIALOG_SCHEDXACTION_EDITOR_CM_CLASS,
+ sxed );
+}
+
+static
+void
+editor_help_button_clicked(GtkButton *b, GncSxEditorDialog *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, GncSxEditorDialog *sxed )
+{
+ GNCBook *book;
+ SchedXactions *sxes;
+
+ if ( !gnc_sxed_check_consistent( sxed ) )
+ return;
+
+ gnc_sxed_save_sx( sxed );
+
+ /* add to list */
+ // @@fixme -- forget 'new'-flag: check for existance.
+ if ( sxed->newsxP ) {
+ book = gnc_get_current_book ();
+ sxes = gnc_book_get_schedxactions(book);
+ gnc_sxes_add_sx(sxes, sxed->sx);
+ sxed->newsxP = FALSE;
+ }
+
+ /* 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( GncSxEditorDialog *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( GncSxEditorDialog *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())->sx_list;
+ 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( GncSxEditorDialog *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, GncSxEditorDialog *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, GncSxEditorDialog *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_editor_dialog_destroy(GtkObject *object, gpointer data)
+{
+ int i;
+ GncSxEditorDialog *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);
+}
+
+static
+gint
+sxed_close_event( GtkDialog *dlg, gpointer ud )
+{
+ GncSxEditorDialog *sxed = (GncSxEditorDialog*)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( GncSxEditorDialog *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);
+
+}
+
+GncSxEditorDialog *
+gnc_ui_scheduled_xaction_editor_dialog_create(SchedXaction *sx,
+ gboolean newSX)
+{
+ GncSxEditorDialog *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 = (GncSxEditorDialog*)dlgExists->data;
+ gtk_window_present( GTK_WINDOW(sxed->dialog) );
+ g_list_free( dlgExists );
+ return sxed;
+ }
+
+ sxed = g_new0( GncSxEditorDialog, 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->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( GncSxEditorDialog *sxed )
+{
+ gnc_save_window_size( SXED_GCONF_SECTION, GTK_WINDOW(sxed->dialog) );
+}
+
+static
+void
+schedXact_editor_create_freq_sel( GncSxEditorDialog *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( GncSxEditorDialog *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( GncSxEditorDialog *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( GncSxEditorDialog *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
+endgroup_rb_toggled( GtkButton *b, gpointer d )
+{
+ /* figure out which one */
+ GncSxEditorDialog *sxed;
+ gint id;
+
+ sxed = (GncSxEditorDialog*)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 );
+}
+
+/********************************************************************\
+ * gnc_register_check_close *
+ * *
+ * Args: regData - the data struct for this register *
+ * Return: none *
+\********************************************************************/
+static void
+gnc_sxed_reg_check_close(GncSxEditorDialog *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
+ == ((GncSxEditorDialog*)user_data)->sx );
+}
+
+typedef enum { NO_END, DATE_END, COUNT_END } END_TYPE;
+
+static
+void
+gnc_sxed_update_cal( GncSxEditorDialog *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( (GncSxEditorDialog*)ud );
+}
+
+static
+void
+sxed_excal_update_adapt( GtkObject *o, gpointer ud )
+{
+ gnc_sxed_update_cal( (GncSxEditorDialog*)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);
+}
+
+
+/* ------------------------------------------------------------ */
+/* sx app engine; move to somewhere appropriate. :/ */
+
+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((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"));
+}
Copied: gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.h (from rev 14507, gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.h)
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-scheduledxaction.h 2006-07-15 15:04:38 UTC (rev 14507)
+++ gnucash/branches/sx-cleanup/src/gnome/dialog-sx-editor.h 2006-07-16 21:35:45 UTC (rev 14521)
@@ -0,0 +1,52 @@
+/********************************************************************\
+ * dialog-sx-editor.h : dialog for scheduled transaction editing *
+ * Copyright (C) 2001,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 *
+\********************************************************************/
+
+#ifndef DIALOG_SX_EDITOR_H
+#define DIALOG_SX_EDITOR_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 _GncSxEditorDialog;
+
+typedef struct _GncSxEditorDialog GncSxEditorDialog;
+
+GncSxEditorDialog *
+gnc_ui_scheduled_xaction_editor_dialog_create(SchedXaction *sx,
+ gboolean newSX);
+
+void gnc_ui_scheduled_xaction_editor_dialog_destroy(GncSxEditorDialog *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
Modified: gnucash/branches/sx-cleanup/src/gnome/dialog-sx-from-trans.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-sx-from-trans.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/dialog-sx-from-trans.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -30,11 +30,10 @@
#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 "gnc-date-edit.h"
@@ -551,7 +550,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 +558,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 +607,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 +623,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. */
Modified: gnucash/branches/sx-cleanup/src/gnome/dialog-sxsincelast.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/dialog-sxsincelast.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/dialog-sxsincelast.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -63,7 +63,6 @@
#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"
@@ -85,7 +84,6 @@
#include "gnc-split-reg.h"
#include "dialog-sxsincelast.h"
-#include "dialog-scheduledxaction.h"
#ifdef HAVE_LANGINFO_D_FMT
#include <langinfo.h>
@@ -1361,7 +1359,7 @@
gpointer arg1, gpointer ud )
{
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
- GList *sxList, *toDelPtr, *elt;
+ GList *toDelPtr;
GtkCList *cl;
gint row;
toDeleteTuple *tdt;
@@ -1384,31 +1382,28 @@
SX_OBSOLETE_CLIST ) );
if ( g_list_length( cl->selection ) > 0 ) {
- SchedXactionDialog *sxd;
- sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
+ GList *to_delete = NULL, *del_iter;
+ SchedXactions *sxes;
- gnc_suspend_gui_refresh();
- for ( toDelPtr = cl->selection;
- toDelPtr;
- toDelPtr = toDelPtr->next ) {
+ sxes = 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 );
+ to_delete = g_list_append(to_delete, tdt->sx);
+ }
- 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 );
+ for (del_iter = to_delete; del_iter != NULL; del_iter = del_iter->next)
+ {
+ SchedXaction* sx = (SchedXaction*)del_iter->data;
+ gnc_sxes_del_sx(sxes, sx);
+ xaccSchedXactionFree(sx);
+ }
+ g_list_free(to_delete);
- 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 );
- }
+ gnc_resume_gui_refresh();
}
sxsincelast_close_handler( sxsld );
@@ -2113,7 +2108,7 @@
toCreateInstance *tci;
instanceList = NULL;
- sxList = gnc_book_get_schedxactions( gnc_get_current_book () );
+ sxList = gnc_book_get_schedxactions(gnc_get_current_book ())->sx_list;
if ( sxList == NULL ) {
DEBUG( "No scheduled transactions to populate." );
Modified: gnucash/branches/sx-cleanup/src/gnome/druid-loan.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/druid-loan.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/druid-loan.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -34,7 +34,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"
@@ -1968,7 +1967,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 );
@@ -1989,9 +1989,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/branches/sx-cleanup/src/gnome/gnc-plugin-basic-commands.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-basic-commands.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-basic-commands.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -41,7 +41,6 @@
#include "dialog-chart-export.h"
#include "dialog-fincalc.h"
#include "dialog-find-transactions.h"
-#include "dialog-scheduledxaction.h"
#include "dialog-sxsincelast.h"
#include "dialog-totd.h"
#include "druid-acct-period.h"
@@ -439,7 +438,6 @@
{
GncPluginPage *page = gnc_plugin_page_sx_list_new();
gnc_main_window_open_page(NULL, page);
- //gnc_ui_scheduled_xaction_dialog_create ();
}
static void
Modified: gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/gnc-plugin-page-sx-list.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -42,6 +42,7 @@
#include "gkeyfile.h"
#endif
#include "gnc-engine.h"
+#include "gnc-event.h"
#include "gnc-dense-cal.h"
#include "gnc-icons.h"
#include "gnc-plugin-page-sx-list.h"
@@ -50,8 +51,8 @@
#include "dialog-utils.h"
#include "gnc-component-manager.h"
#include "SX-book.h"
-#include "SX-book-p.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;
@@ -207,7 +208,9 @@
static void gppsl_event_handler(QofEntity *ent, QofEventId event_type, gpointer user_data, gpointer evt_data);
+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);
@@ -367,7 +370,6 @@
GtkAction *edit_action, *delete_action;
gboolean selection_state = TRUE;
- printf("selection changed\n");
page = GNC_PLUGIN_PAGE(user_data);
edit_action = gnc_plugin_page_get_action(page, "SxListEditAction");
delete_action = gnc_plugin_page_get_action(page, "SxListDeleteAction");
@@ -405,6 +407,14 @@
}
{
+ 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;
@@ -433,7 +443,7 @@
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(tree_view), "row-activated", (GCallback)gppsl_row_activate_cb, (gpointer)page);
+ g_signal_connect(G_OBJECT(priv->tree_view), "row-activated", (GCallback)gppsl_row_activated_cb, (gpointer)page);
}
{
@@ -564,37 +574,87 @@
/* 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)
{
- printf("new\n");
+ 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)
{
- printf("edit\n");
+ 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 = g_list_map(selected_paths, (GMapFunc)_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 SchedXaction*
-_sx_for_iter(gpointer data, gpointer user_data)
+static void
+gppsl_row_activated_cb(GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ 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;
+ 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;
- GList *book_sxes;
book = gnc_get_current_book();
- book_sxes = gnc_book_get_schedxactions(book);
- book_sxes = g_list_remove(book_sxes, sx);
- gnc_book_set_schedxactions(book, book_sxes);
+ sxes = gnc_book_get_schedxactions(book);
+ gnc_sxes_del_sx(sxes, sx);
xaccSchedXactionFree(sx);
}
@@ -605,6 +665,8 @@
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);
@@ -614,7 +676,7 @@
return;
}
- to_delete = g_list_map(selected_paths, (GMapFunc)_sx_for_iter, model);
+ to_delete = g_list_map(selected_paths, (GMapFunc)_sx_for_path, model);
{
GList *list;
for (list = to_delete; list != NULL; list = list->next)
@@ -626,8 +688,83 @@
g_list_free(to_delete);
g_list_foreach(selected_paths, (GFunc)gtk_tree_path_free, NULL);
g_list_free(selected_paths);
- }
+}
+#if 0 // compare/sort fns
+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 );
+}
+
+#endif // 0 - compare/sort fns
+
/* ------------------------------------------------------------ */
static GncSxInstances*
@@ -649,7 +786,7 @@
// postponed
{
- // defer list.
+ // @@fixme - defer list.
}
// to-create
@@ -708,7 +845,7 @@
instances = gnc_sx_instance_model_new();
instances->range_end = *range_end;
- sxes = gnc_book_get_schedxactions(gnc_get_current_book());
+ sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
instances->sx_instance_list = g_list_map(sxes, (GMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
return instances;
@@ -788,41 +925,62 @@
_gnc_sx_instance_event_handler(QofEntity *ent, QofEventId event_type, gpointer user_data, gpointer evt_data)
{
GncSxInstanceModel *instances = GNC_SX_INSTANCE_MODEL(user_data);
- SchedXaction *sx;
- if (!GNC_IS_SX(ent))
+ // selection rules {
+ // (gnc_collection_get_schedxaction_list(book), GNC_EVENT_ITEM_ADDED)
+ // (gnc_collection_get_schedxaction_list(book), GNC_EVENT_ITEM_REMOVED)
+ // (GNC_IS_SX(ent), QOF_EVENT_MODIFIED)
+ // }
+ if (!(GNC_IS_SX(ent) || GNC_IS_SXES(ent)))
return;
- sx = GNC_SX(ent);
- if (event_type & QOF_EVENT_DESTROY)
+ if (GNC_IS_SX(ent))
{
- gpointer sx_instance_to_remove = NULL;
- GList *list;
- // find, remove, update
- for (list = instances->sx_instance_list; list != NULL; list = list->next)
+ SchedXaction *sx;
+ sx = GNC_SX(ent);
+ if (event_type & QOF_EVENT_MODIFY)
{
- if (sx == ((GncSxInstances*)list->data)->sx)
+ // @re-generate instance, update
+ }
+ /* else { unsupported event type; ignore } */
+ }
+ else if (GNC_IS_SXES(ent))
+ {
+ SchedXactions *sxes = GNC_SXES(ent);
+ SchedXaction *sx = GNC_SX(evt_data);
+
+ sxes = NULL;
+ if (event_type & GNC_EVENT_ITEM_REMOVED)
+ {
+ gpointer sx_instance_to_remove = NULL;
+ GList *list;
+
+ // find, remove, update
+ for (list = instances->sx_instance_list; list != NULL; list = list->next)
{
- sx_instance_to_remove = list->data;
- break;
+ if (sx == ((GncSxInstances*)list->data)->sx)
+ {
+ sx_instance_to_remove = list->data;
+ break;
+ }
}
+ if (sx_instance_to_remove != NULL)
+ {
+ instances->sx_instance_list = g_list_remove(instances->sx_instance_list, sx_instance_to_remove);
+ g_signal_emit_by_name(instances, "updated");
+ }
+ else { printf("err\n"); }
}
- if (sx_instance_to_remove != NULL)
+ else if (event_type & GNC_EVENT_ITEM_ADDED)
{
- instances->sx_instance_list = g_list_remove(instances->sx_instance_list, sx_instance_to_remove);
+ // generate instances, add to instance list, emit update.
+ instances->sx_instance_list
+ = g_list_append(instances->sx_instance_list,
+ (*_gnc_sx_gen_instances)((gpointer)sx, (gpointer)&instances->range_end));
g_signal_emit_by_name(instances, "updated");
}
- else { printf("err\n"); }
+ // else { printf("unsupported event type [%d]\n", event_type); }
}
- else if (event_type & QOF_EVENT_CREATE)
- {
- // add, update
- g_signal_emit_by_name(instances, "updated");
- }
- else { printf("unknown\n"); }
- /* else { unsupported event type; ignore } */
-
- instances = 0;
}
@@ -1005,7 +1163,6 @@
g_signal_emit_by_name(user_data, "row-deleted", arg1);
}
-
static void
gsltma_proxy_row_has_child_toggled(GtkTreeModel *treemodel,
GtkTreePath *arg1,
@@ -1015,7 +1172,6 @@
g_signal_emit_by_name(user_data, "row-has-child-toggled", arg1, arg2);
}
-
static void
gsltma_proxy_row_inserted(GtkTreeModel *treemodel,
GtkTreePath *arg1,
@@ -1025,7 +1181,6 @@
g_signal_emit_by_name(user_data, "row-inserted", arg1, arg2);
}
-
static void
gsltma_proxy_rows_reordered(GtkTreeModel *treemodel,
GtkTreePath *arg1,
@@ -1050,7 +1205,7 @@
}
static void
-gsltma_populate(GncSxListTreeModelAdapter *model)
+gsltma_populate_tree_store(GncSxListTreeModelAdapter *model)
{
GtkTreeIter iter;
GList *list;
@@ -1063,7 +1218,6 @@
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);
@@ -1099,9 +1253,9 @@
gsltma_updated_cb(GncSxInstanceModel *instances, gpointer user_data)
{
GncSxListTreeModelAdapter *model = GNC_SX_LIST_TREE_MODEL_ADAPTER(user_data);
- printf("update!\n");
+ printf("update\n");
gtk_tree_store_clear(model->real);
- gsltma_populate(model);
+ gsltma_populate_tree_store(model);
}
GncSxListTreeModelAdapter*
@@ -1112,8 +1266,7 @@
rtn = GNC_SX_LIST_TREE_MODEL_ADAPTER(g_object_new(GNC_TYPE_SX_LIST_TREE_MODEL_ADAPTER, NULL));
rtn->instances = instances;
- // copy data over...
- gsltma_populate(rtn);
+ gsltma_populate_tree_store(rtn);
g_signal_connect(G_OBJECT(rtn->instances), "updated", (GCallback)gsltma_updated_cb, (gpointer)rtn);
Modified: gnucash/branches/sx-cleanup/src/gnome/gnc-split-reg.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/gnc-split-reg.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/gnc-split-reg.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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;
}
}
Modified: gnucash/branches/sx-cleanup/src/gnome/gw-gnc-spec.scm
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/gw-gnc-spec.scm 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/gw-gnc-spec.scm 2006-07-16 21:35:45 UTC (rev 14521)
@@ -46,7 +46,7 @@
"#include <gnc-window.h>\n"
"#include <gnc-plugin-account-tree.h>\n"
"#include <gnc-splash.h>\n"
- "#include <dialog-scheduledxaction.h>\n"
+ "#include <dialog-sx-editor.h>\n"
"#include <dialog-sxsincelast.h>\n" )))
(gw:wrap-function
Modified: gnucash/branches/sx-cleanup/src/gnome/top-level.c
===================================================================
--- gnucash/branches/sx-cleanup/src/gnome/top-level.c 2006-07-16 16:58:07 UTC (rev 14520)
+++ gnucash/branches/sx-cleanup/src/gnome/top-level.c 2006-07-16 21:35:45 UTC (rev 14521)
@@ -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"
More information about the gnucash-changes
mailing list