2002-10-06 Joshua Sled <jsled@asynchronous.org>

* src/gnome/druid-loan.c: The druid now enforces valid account
	selection for the GNCAccountSel widgets; fixes Bug#90784.

	* src/gnome/gnc-account-sel.c (gas_destroy): GNCAccountSel
	now cleans up after itself, especially with removing its engine
	event observation.  Moved from src/gnome-utils/ to src/gnome/
	because of circular dep introduced below.

	* src/dialog-account/dialog-account.c
	(gnc_ui_new_account_with_types): Added new function to create a
	NewAccount dialog with only a valid-types filtering list.

	* src/gnome-utils/gnc-account-sel.c
	(gnc_account_sel_set_acct_filters): Added support for filtering
	the accounts available through the GNCAccountSel.
	(gnc_account_sel_set_new_account_ability): Added support for a
	conditional "New..." button which allows the creation a new
	account.  If the selector has a filter in place, the filter will
	apply to the new-account creation as well.

	* src/gnome-utils/gnc-account-sel.c: Added ifdefs, comments around
	regions pertaining to unimplemented feature of completion.
	Fix for Bug#90779.
	(gnc_account_sel_event_cb): Added support for updating list
	contents when the account tree changes; the current selection is
	respected if the account still exists; fixes Bug#94951.

	* src/gnome/dialog-sxsincelast.c
	(sxsld_process_to_create_instance): Handle the corner case of not
	incrementing the state while postponing/ignoring a
	never-been-created SX.  Handle only incrementing the counters of
	newly-come-due SXes.

	* src/engine/SchedXaction.c (gnc_sx_create_temporal_state): Fix
	corner case of creating the temporal state of a never-been-created
	SX; fixes Bug#94947.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7283 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled
2002-10-06 22:31:05 +00:00
parent 354de817c7
commit b7ed99154a
15 changed files with 694 additions and 400 deletions
+39
View File
@@ -1,3 +1,42 @@
2002-10-06 Joshua Sled <jsled@asynchronous.org>
* src/gnome/druid-loan.c: The druid now enforces valid account
selection for the GNCAccountSel widgets; fixes Bug#90784.
* src/gnome/gnc-account-sel.c (gas_destroy): GNCAccountSel
now cleans up after itself, especially with removing its engine
event observation. Moved from src/gnome-utils/ to src/gnome/
because of circular dep introduced below.
* src/dialog-account/dialog-account.c
(gnc_ui_new_account_with_types): Added new function to create a
NewAccount dialog with only a valid-types filtering list.
* src/gnome-utils/gnc-account-sel.c
(gnc_account_sel_set_acct_filters): Added support for filtering
the accounts available through the GNCAccountSel.
(gnc_account_sel_set_new_account_ability): Added support for a
conditional "New..." button which allows the creation a new
account. If the selector has a filter in place, the filter will
apply to the new-account creation as well.
* src/gnome-utils/gnc-account-sel.c: Added ifdefs, comments around
regions pertaining to unimplemented feature of completion.
Fix for Bug#90779.
(gnc_account_sel_event_cb): Added support for updating list
contents when the account tree changes; the current selection is
respected if the account still exists; fixes Bug#94951.
* src/gnome/dialog-sxsincelast.c
(sxsld_process_to_create_instance): Handle the corner case of not
incrementing the state while postponing/ignoring a
never-been-created SX. Handle only incrementing the counters of
newly-come-due SXes.
* src/engine/SchedXaction.c (gnc_sx_create_temporal_state): Fix
corner case of creating the temporal state of a never-been-created
SX; fixes Bug#94947.
2002-10-06 Christian Stimming <stimming@tuhh.de>
* src/import-export/hbci/gnc-hbci-gettrans.c, gnc-hbci-actions.c:
+9
View File
@@ -40,6 +40,15 @@ AccountWindow * gnc_ui_new_account_window_with_default(AccountGroup *group,
Account * parent);
AccountWindow * gnc_ui_edit_account_window (Account *account);
/**
* @param unused The AccountGroup to create in; this isn't used.
* @param valid_types A GList of GNCAccountType gints [as pointers] which are
* allowed to be created. Unlike below, this function makes a copy of the
* valid_types list.
**/
AccountWindow * gnc_ui_new_account_with_types( AccountGroup *unused,
GList *valid_types );
Account * gnc_ui_new_accounts_from_name_window (const char *name);
/* Note that the caller owns the valid_types list */
+1
View File
@@ -363,6 +363,7 @@ test_files_in_dir(int argc, char **argv, gxpf_callback cb,
{
if(!S_ISDIR(file_info.st_mode))
{
printf( "testing load of file \"%s\":\n", argv[count] );
test_load_file(to_open, cb, parser, parser_tag, book);
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ for i in $SRCDIR/test-files/xml2/*.gml2 ; do
FILES=`perl $SRCDIR/grab-types.pl "gnc:$j" $i "$j/dataXXX.xml"`
if [ ! -z "$FILES" ] ; then
echo "Testing file `basename $i`, section $j"
echo "[./test-xml-$j $FILES # from file $i]:"
eval "./test-xml-$j $FILES"
if [ $? != 0 ] ; then
EXIT_VALUE=1
@@ -139,6 +139,11 @@ equals_node_val_vs_split_internal(xmlNodePtr node, Split* spl)
gnc_numeric *num = dom_tree_to_gnc_numeric(mark);
gnc_numeric val = xaccSplitGetAmount(spl);
if ( gnc_numeric_equal(*num, val)) {
return g_strdup_printf( "quantities differ under _equal: %lld/%lld v %lld/%lld",
(*num).num, (*num).denom,
val.num, val.denom );
}
if(!gnc_numeric_eq(*num, val))
{
g_free(num);
+21 -2
View File
@@ -147,6 +147,7 @@ delete_template_trans(SchedXaction *sx)
void
xaccSchedXactionFree( SchedXaction *sx )
{
GList *l;
if ( sx == NULL ) return;
@@ -171,10 +172,19 @@ xaccSchedXactionFree( SchedXaction *sx )
xaccAccountBeginEdit(sx->template_acct);
xaccAccountDestroy(sx->template_acct);
for ( l = sx->deferredList; l; l = l->next ) {
gnc_sx_destroy_temporal_state( l->data );
l->data = NULL;
}
if ( sx->deferredList ) {
g_list_free( sx->deferredList );
sx->deferredList = NULL;
}
g_free( sx );
return;
return;
}
@@ -489,12 +499,16 @@ xaccSchedXactionGetInstanceAfter( SchedXaction *sx,
{
GDate prev_occur, next_occur;
prev_occur = *date;
g_date_clear( &prev_occur, 1 );
if ( date ) {
prev_occur = *date;
}
if ( stateData != NULL ) {
temporalStateData *tsd = (temporalStateData*)stateData;
prev_occur = tsd->last_date;
}
if ( ! g_date_valid( &prev_occur ) ) {
/* We must be at the beginning. */
prev_occur = sx->start_date;
@@ -679,6 +693,10 @@ gnc_sx_create_temporal_state( SchedXaction *sx )
temporalStateData *toRet =
g_new0( temporalStateData, 1 );
toRet->last_date = sx->last_date;
if ( !g_date_valid( &toRet->last_date ) ) {
toRet->last_date = sx->start_date;
g_date_subtract_days( &toRet->last_date, 1 );
}
toRet->num_occur_rem = sx->num_occurances_remain;
toRet->num_inst = sx->instance_num;
return (void*)toRet;
@@ -690,6 +708,7 @@ gnc_sx_incr_temporal_state( SchedXaction *sx, void *stateData )
GDate unused;
temporalStateData *tsd = (temporalStateData*)stateData;
g_date_clear( &unused, 1 );
tsd->last_date =
xaccSchedXactionGetInstanceAfter( sx,
&unused,
-2
View File
@@ -25,7 +25,6 @@ libgncmod_gnome_utils_la_SOURCES = \
dialog-options.c \
dialog-utils.c \
druid-utils.c \
gnc-account-sel.c \
gnc-account-tree.c \
gnc-amount-edit.c \
gnc-commodity-edit.c \
@@ -53,7 +52,6 @@ gncinclude_HEADERS = \
dialog-options.h \
dialog-utils.h \
druid-utils.h \
gnc-account-sel.h \
gnc-account-tree.h \
gnc-amount-edit.h \
gnc-commodity-edit.h \
-301
View File
@@ -1,301 +0,0 @@
/**
* gnc-account-sel.c -- combobox style account selection widget, with
* auto-completion.
*
* Copyright (C) 2002 Joshua Sled <jsled@asynchronous.org>
* All rights reserved.
*
* Gnucash is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* Gnucash 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
* Library 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
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652
* Boston, MA 02111-1307, USA gnu@gnu.org
**/
#include "config.h"
#include "gnc-account-sel.h"
#include "gnc-exp-parser.h"
#include "messages.h"
#include "gnc-ui-util.h"
#include "gnc-engine-util.h"
#define ACCT_DATA_TAG "gnc-account-sel_acct"
/* Signal codes */
enum
{
ACCOUNT_SEL_CHANGED,
LAST_SIGNAL
};
static gint account_sel_signals [LAST_SIGNAL] = { 0 };
static void gnc_account_sel_init (GNCAccountSel *gas);
static void gnc_account_sel_class_init (GNCAccountSelClass *class);
static void gas_accounts_to_names( gpointer data, gpointer user_data );
#if 0
static void gnc_account_sel_changed( GtkEditable *entry, gpointer ud );
static void gnc_account_sel_list_clicked( GtkButton *b, gpointer ud );
static gint gnc_account_sel_key_press( GtkWidget *widget,
GdkEventKey *event );
#endif /* 0 */
static GtkHBox *parent_class;
guint
gnc_account_sel_get_type (void)
{
static guint account_sel_type = 0;
if (!account_sel_type){
GtkTypeInfo account_sel_info = {
"GNCAccountSel",
sizeof (GNCAccountSel),
sizeof (GNCAccountSelClass),
(GtkClassInitFunc) gnc_account_sel_class_init,
(GtkObjectInitFunc) gnc_account_sel_init,
NULL,
NULL,
(GtkClassInitFunc) NULL,
};
account_sel_type = gtk_type_unique (GTK_TYPE_HBOX, &account_sel_info);
}
return account_sel_type;
}
static void
gnc_account_sel_class_init (GNCAccountSelClass *class)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkHBoxClass *hbox_class;
object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
hbox_class = (GtkHBoxClass*) class;
parent_class = gtk_type_class (gtk_entry_get_type ());
account_sel_signals [ACCOUNT_SEL_CHANGED] =
gtk_signal_new ("account_sel_changed",
GTK_RUN_FIRST, object_class->type,
GTK_SIGNAL_OFFSET (GNCAccountSelClass,
account_sel_changed),
gtk_signal_default_marshaller,
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class,
account_sel_signals,
LAST_SIGNAL);
class->account_sel_changed = NULL;
}
typedef struct {
GList **outList;
char accountSep;
} accounts_to_names_data;
static void
gnc_account_sel_init (GNCAccountSel *gas)
{
gas->initDone = FALSE;
gas->combo = GTK_COMBO(gtk_combo_new());
gtk_container_add( GTK_CONTAINER(gas), GTK_WIDGET(gas->combo) );
gtk_editable_set_editable( GTK_EDITABLE(gas->combo->entry), FALSE );
#if 0
gtk_signal_connect( GTK_OBJECT(gas->combo->entry), "changed",
GTK_SIGNAL_FUNC( gnc_account_sel_changed ),
gas );
#endif /* 0 */
/* Get the accounts, place into combo list and setup GCompletion */
{
accounts_to_names_data atnd;
AccountGroup *ag;
GList *accts, *nameList;
ag = gnc_book_get_group( gnc_get_current_book() );
accts = (GList*)xaccGroupGetSubAccounts( ag );
nameList = NULL;
atnd.outList = &nameList;
atnd.accountSep = gnc_get_account_separator();
g_list_foreach( accts, gas_accounts_to_names,
(gpointer)&atnd );
g_list_free( accts );
gtk_combo_set_popdown_strings( gas->combo, nameList );
gas->completion = g_completion_new( NULL );
g_completion_add_items( gas->completion, nameList );
}
gas->initDone = TRUE;
}
static
void
gas_accounts_to_names( gpointer data, gpointer user_data )
{
accounts_to_names_data *atnd;
Account *a;
atnd = (accounts_to_names_data*)user_data;
a = (Account*)data;
*atnd->outList =
g_list_append( *atnd->outList,
xaccAccountGetFullName(a, atnd->accountSep) );
}
#if 0 /* fscking gtk... */
/*
* There is apparently no way -- in GTK 1.x -- to programatically select a
* region in the way we would like... so we've disallowed manual editing of
* the Account string.
*/
static
void
gnc_account_sel_changed( GtkEditable *entry, gpointer ud )
{
gchar *s, *prefix;
GNCAccountSel *gas = (GNCAccountSel*)ud;
if ( !gas->initDone ) {
return;
}
s = gtk_editable_get_chars( entry, 0, -1 );
g_completion_complete( gas->completion, s, &prefix );
if ( prefix && (strlen(prefix) > 0) ) {
printf( "changed into \"%s\"; longest completion: \"%s\"\n", s, prefix );
gtk_signal_handler_block_by_func( GTK_OBJECT(gas->combo->entry),
GTK_SIGNAL_FUNC(gnc_account_sel_changed),
ud );
gtk_entry_set_text( GTK_ENTRY(gas->combo->entry), prefix );
gtk_editable_select_region( GTK_EDITABLE(gas->combo->entry),
strlen(s), -1 );
{
GdkEventKey k;
gboolean ret;
k.type = GDK_KEY_RELEASE;
k.send_event = TRUE;
k.state = GDK_SHIFT_MASK;
k.keyval = GDK_End;
k.length = 0;
k.string = "";
printf( "foo [%d : \"%s\"]\n", k.length, k.string );
//gtk_widget_event( GTK_WIDGET(gas->combo->entry), &e );
gtk_signal_emit_by_name( GTK_OBJECT(gas->combo->entry),
"key-press-event",
gas->combo->entry, &k, NULL, &ret );
printf( "bar\n" );
}
gtk_editable_set_position( GTK_EDITABLE(gas->combo->entry),
strlen(s) );
gtk_signal_handler_unblock_by_func( GTK_OBJECT(gas->combo->entry),
GTK_SIGNAL_FUNC(gnc_account_sel_changed),
ud );
g_free( prefix );
}
g_free( s );
}
static
gint
gnc_account_sel_key_press(GtkWidget *widget, GdkEventKey *event)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(widget);
gint result;
result = (* GTK_WIDGET_CLASS (parent_class)->key_press_event)(widget, event);
switch (event->keyval)
{
case GDK_Tab:
/* FIXME: += equivalent. */
break;
#if 0
case GDK_DOWN:
/* dispaly combobox */
break;
#endif /* 0 */
case GDK_Return:
#if 0
if (gae->evaluate_on_enter)
break;
#endif /* 0 */
if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SHIFT_MASK))
break;
return result;
case GDK_KP_Enter:
break;
default:
return result;
}
return TRUE;
}
#endif /* 0 */
GtkWidget *
gnc_account_sel_new (void)
{
GNCAccountSel *gas;
gas = gtk_type_new (gnc_account_sel_get_type ());
return GTK_WIDGET (gas);
}
GtkWidget *
gnc_account_sel_gtk_entry (GNCAccountSel *gas)
{
g_return_val_if_fail(gas != NULL, NULL);
g_return_val_if_fail(GNC_IS_ACCOUNT_SEL(gas), NULL);
return (GtkWidget *)gas->combo->entry;
}
void
gnc_account_sel_set_account( GNCAccountSel *gas, Account *acct )
{
gchar *acctStr;
if ( acct == NULL ) {
gtk_list_select_item( GTK_LIST(gas->combo->list), 0 );
return;
}
acctStr = xaccAccountGetFullName( acct,
gnc_get_account_separator() );
gtk_entry_set_text( GTK_ENTRY(gas->combo->entry), acctStr );
g_free( acctStr );
}
Account*
gnc_account_sel_get_account( GNCAccountSel *gas )
{
AccountGroup *ag;
Account *ret;
gchar *txt;
txt = gtk_editable_get_chars( GTK_EDITABLE(gas->combo->entry), 0, -1 );
ag = gnc_book_get_group( gnc_get_current_book() );
ret = xaccGetAccountFromFullName( ag, txt, gnc_get_account_separator() );
g_free( txt );
return ret;
}
+2
View File
@@ -43,6 +43,7 @@ libgncgnome_la_SOURCES = \
druid-hierarchy.c \
druid-loan.c \
druid-stock-split.c \
gnc-account-sel.c \
gnc-network.c \
gnc-splash.c \
mainwindow-account-tree.c \
@@ -79,6 +80,7 @@ noinst_HEADERS = \
dialog-scheduledxaction.h \
druid-hierarchy.h \
druid-loan.h \
gnc-account-sel.h \
gnc-network.h \
gnc-splash.h \
gw-gnc.h \
+37 -15
View File
@@ -1092,6 +1092,13 @@ sxsld_process_to_create_instance( sxSinceLastData *sxsld,
break;
}
/* add to the postponed list. */
{
char tmpBuf[50];
g_date_strftime( tmpBuf, 49, "%c", tci->date );
DEBUG( "Adding defer instance on %s for %s",
tmpBuf,
xaccSchedXactionGetName( tci->parentTCT->sx ) );
}
gnc_sx_add_defer_instance( tci->parentTCT->sx, tci->sxStateData );
break;
case TO_CREATE:
@@ -1128,11 +1135,18 @@ sxsld_process_to_create_instance( sxSinceLastData *sxsld,
return;
}
xaccSchedXactionSetLastOccurDate( sx, tci->date );
tmp = gnc_sx_get_instance_count( sx, NULL );
gnc_sx_set_instance_count( sx, tmp+1 );
if ( xaccSchedXactionHasOccurDef( sx ) ) {
tmp = xaccSchedXactionGetRemOccur(sx);
xaccSchedXactionSetRemOccur( sx, tmp-1 );
/* Handle an interesting corner case of postponing or
* ignoring the first instance. We only want to incrment the
* counters for newly-discovered-as-to-be-created SXes.
*/
if ( tci->origState == UNDEF ) {
tmp = gnc_sx_get_instance_count( sx, NULL );
gnc_sx_set_instance_count( sx, tmp+1 );
if ( xaccSchedXactionHasOccurDef( sx ) ) {
tmp = xaccSchedXactionGetRemOccur(sx);
xaccSchedXactionSetRemOccur( sx, tmp-1 );
}
}
}
}
@@ -1288,6 +1302,8 @@ cancel_check( GnomeDruidPage *druid_page,
"Are you sure you want to lose all "
"Scheduled Transaction changes?" );
/* FIXME: This may now be a bug, as we might have changed the SX
* states. */
if ( g_list_length( sxsld->createdTxnGUIDList ) == 0 ) {
/* There's nothing to cancel, so just do so... */
return FALSE;
@@ -1347,7 +1363,7 @@ cancel_check( GnomeDruidPage *druid_page,
tciList = tciList->next ) {
tci = (toCreateInstance*)tciList->data;
if ( tci->prevState == POSTPONE
&& tci->origState != POSTPONE ) {
&& tci->origState != POSTPONE ) {
/* Any valid [non-null] 'prevState !=
* POSTPONE' sx temporal state
* pointers will be destroyed at the
@@ -1540,6 +1556,8 @@ generate_instances( SchedXaction *sx,
g_assert( g_date_valid(end) );
g_assert( g_date_valid(reminderEnd) );
g_date_clear( &gd, 1 );
/* Process valid next instances. */
seqStateData = gnc_sx_create_temporal_state( sx );
//gd = xaccSchedXactionGetNextInstance( sx, seqStateData );
@@ -1961,7 +1979,6 @@ sxsincelast_populate( sxSinceLastData *sxsld )
GList *sxList, *instanceList, *l, **containingList;
SchedXaction *sx;
void *sx_state;
GDate end, endPlusReminders;
gint daysInAdvance;
gboolean autocreateState, notifyState;
@@ -1991,9 +2008,13 @@ sxsincelast_populate( sxSinceLastData *sxsld )
"the first time?" );
return FALSE;
}
sx_state = gnc_sx_create_temporal_state( sx );
g_hash_table_insert( sxsld->sxInitStates,
sx, sx_state );
{
void *sx_state;
sx_state = gnc_sx_create_temporal_state( sx );
g_hash_table_insert( sxsld->sxInitStates,
sx, sx_state );
sx_state = NULL;
}
g_date_set_time( &end, time(NULL) );
daysInAdvance = xaccSchedXactionGetAdvanceCreation( sx );
@@ -3474,21 +3495,22 @@ gnc_sxsld_free_tci( toCreateInstance *tci )
* but here's the rules...
*
* If we're not cancelling...
* . If ignored, then destroy.
* . If postponed, then don't.
* . If ignored, destroy.
* . If postponed, DON'T destroy.
* . If to-create, destroy.
*
* If we are cancelling....
* If we are cancelling...
* . If ignored, destroy.
* . If postponed, destroy.
* . UNLESS previously postponed
* . If to-create, destroy.
*
* So, we don't destroy postponed by default, and let the
* cancel-specific case handle that destruction [thus the
* valid-pointer check].
*/
if ( tci->prevState != POSTPONE
&& tci->origState != POSTPONE
if ( tci->prevState != POSTPONE
&& tci->origState != POSTPONE
&& tci->sxStateData != NULL ) {
gnc_sx_destroy_temporal_state( tci->sxStateData );
tci->sxStateData = NULL;
+62 -10
View File
@@ -334,6 +334,7 @@ gnc_ui_sx_loan_druid_create()
a = GTK_ALIGNMENT(gtk_alignment_new( 0.0, 0.5, 0.25, 1.0 ));
gas = GNC_ACCOUNT_SEL(gnc_account_sel_new());
gnc_account_sel_set_new_account_ability( gas, TRUE );
gtk_container_add( GTK_CONTAINER(a),
GTK_WIDGET(gas) );
gtk_table_attach( gas_data[i].table,
@@ -402,6 +403,7 @@ gnc_ui_sx_loan_druid_create()
GTK_SIGNAL_FUNC(ld_escrow_toggle), ldd );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), FALSE );
ldd->optEscrowGAS = GNC_ACCOUNT_SEL(gnc_account_sel_new());
gnc_account_sel_set_new_account_ability( ldd->optEscrowGAS, TRUE );
gtk_container_add( GTK_CONTAINER(ldd->optEscrowHBox),
GTK_WIDGET(ldd->optEscrowGAS) );
@@ -820,6 +822,12 @@ ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
ldd = (LoanDruidData*)ud;
ldd->ld.primaryAcct = gnc_account_sel_get_account( ldd->prmAccountGAS );
if ( ldd->ld.primaryAcct == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"loan account." );
return TRUE;
}
if ( ! ldd->ld.repPriAcct ) {
ldd->ld.repPriAcct = ldd->ld.primaryAcct;
}
@@ -896,23 +904,30 @@ ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
}
static
void
gboolean
ld_opts_save_state( LoanDruidData *ldd )
{
if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb) ) ) {
ldd->ld.escrowAcct =
gnc_account_sel_get_account( ldd->optEscrowGAS );
if ( ldd->ld.escrowAcct == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"Escrow Account" );
return TRUE;
}
} else {
ldd->ld.escrowAcct = NULL;
}
return FALSE;
}
static
gboolean
ld_opts_tran( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
{
ld_opts_save_state( (LoanDruidData*)ud );
return FALSE;
return ld_opts_save_state( (LoanDruidData*)ud );
}
static
@@ -944,7 +959,7 @@ ld_opts_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
}
static
void
gboolean
ld_rep_save( LoanDruidData *ldd )
{
int i;
@@ -961,10 +976,28 @@ ld_rep_save( LoanDruidData *ldd )
ldd->ld.repFromAcct =
gnc_account_sel_get_account( ldd->repAssetsFromGAS );
if ( ldd->ld.repFromAcct == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"\"from\" account." );
return TRUE;
}
ldd->ld.repPriAcct =
gnc_account_sel_get_account( ldd->repPrincToGAS );
if ( ldd->ld.repPriAcct == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"\"to\" account." );
return TRUE;
}
ldd->ld.repIntAcct =
gnc_account_sel_get_account( ldd->repIntToGAS );
if ( ldd->ld.repIntAcct == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"\"interest\" account." );
return TRUE;
}
ldd->ld.remainderChoice =
gnc_option_menu_get_active( GTK_WIDGET(ldd->repRemainderOpt) );
gnc_frequency_save_state( ldd->repGncFreq,
@@ -979,6 +1012,7 @@ ld_rep_save( LoanDruidData *ldd )
rod->from = ldd->ld.repFromAcct;
}
}
return FALSE;
}
static
@@ -989,7 +1023,9 @@ ld_rep_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
ldd = (LoanDruidData*)ud;
ld_rep_save( ldd );
if ( ld_rep_save( ldd ) != FALSE ) {
return TRUE;
}
if ( (ldd->currentIdx < 0)
|| (ldd->currentIdx >= ldd->ld.repayOptCount)
@@ -1019,8 +1055,7 @@ ld_rep_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
LoanDruidData *ldd;
ldd = (LoanDruidData*)ud;
ld_rep_save(ldd);
return FALSE;
return ld_rep_save(ldd);
}
static
@@ -1107,7 +1142,7 @@ ld_pay_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
}
static
void
gboolean
ld_pay_save_current( LoanDruidData *ldd )
{
gchar *tmpStr;
@@ -1131,7 +1166,19 @@ ld_pay_save_current( LoanDruidData *ldd )
g_free( tmpStr );
rod->from = gnc_account_sel_get_account( ldd->payAcctFromGAS );
if ( rod->from == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"\"from\" account." );
return TRUE;
}
rod->to = gnc_account_sel_get_account( ldd->payAcctToGAS );
if ( rod->from == NULL ) {
gnc_info_dialog_parented( GTK_WINDOW(ldd->dialog),
"Please select a valid "
"\"to\" account." );
return TRUE;
}
/* if ( rb toggled )
* ensure freqspec/startdate setup
@@ -1164,6 +1211,7 @@ ld_pay_save_current( LoanDruidData *ldd )
rod->startDate = NULL;
}
}
return FALSE;
}
static
@@ -1175,7 +1223,9 @@ ld_pay_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
ldd = (LoanDruidData*)ud;
/* save current data */
ld_pay_save_current( ldd );
if ( ld_pay_save_current( ldd ) != FALSE ) {
return TRUE;
}
/* Go through opts list and select next enabled option. */
for ( i=(++ldd->currentIdx);
@@ -1200,7 +1250,9 @@ ld_pay_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud )
ldd = (LoanDruidData*)ud;
/* save current data */
ld_pay_save_current( ldd );
if ( ld_pay_save_current( ldd ) != FALSE ) {
return TRUE;
}
for ( i=(--ldd->currentIdx);
(i > -1) && !ldd->ld.repayOpts[i]->enabled;
-56
View File
@@ -5565,60 +5565,4 @@ Escrow
</widget>
</widget>
<widget>
<class>GtkMenu</class>
<name>Since Last Run popup</name>
<widget>
<class>GtkMenuItem</class>
<name>creation_state</name>
<label>Creation State</label>
<right_justify>False</right_justify>
<widget>
<class>GtkMenu</class>
<name>creation_state_menu</name>
<widget>
<class>GtkPixmapMenuItem</class>
<name>ignore</name>
<signal>
<name>activate</name>
<handler>on_ignore_activate</handler>
<last_modification_time>Fri, 23 Aug 2002 22:16:45 GMT</last_modification_time>
</signal>
<label>Ignore</label>
<right_justify>False</right_justify>
<stock_icon>GNOME_STOCK_MENU_STOP</stock_icon>
</widget>
<widget>
<class>GtkPixmapMenuItem</class>
<name>postpone</name>
<signal>
<name>activate</name>
<handler>on_postpone_activate</handler>
<last_modification_time>Fri, 23 Aug 2002 22:16:45 GMT</last_modification_time>
</signal>
<label>Postpone</label>
<right_justify>False</right_justify>
<stock_icon>GNOME_STOCK_MENU_TIMER_STOP</stock_icon>
</widget>
<widget>
<class>GtkPixmapMenuItem</class>
<name>create</name>
<signal>
<name>activate</name>
<handler>on_create_activate</handler>
<last_modification_time>Fri, 23 Aug 2002 22:16:45 GMT</last_modification_time>
</signal>
<label>Create</label>
<right_justify>False</right_justify>
<stock_icon>GNOME_STOCK_MENU_TIMER</stock_icon>
</widget>
</widget>
</widget>
</widget>
</GTK-Interface>
+477
View File
@@ -0,0 +1,477 @@
/**
* gnc-account-sel.c -- combobox style account selection widget
*
* Copyright (C) 2002 Joshua Sled <jsled@asynchronous.org>
* All rights reserved.
*
* Gnucash is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* Gnucash 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
* Library 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
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652
* Boston, MA 02111-1307, USA gnu@gnu.org
**/
#include "config.h"
#include "AccWindow.h"
#include "gnc-account-sel.h"
#include "gnc-exp-parser.h"
#include "messages.h"
#include "gnc-ui-util.h"
#include "gnc-engine-util.h"
#include "gnc-event.h"
#define ACCT_DATA_TAG "gnc-account-sel_acct"
/* Signal codes */
enum
{
ACCOUNT_SEL_CHANGED,
LAST_SIGNAL
};
static gint account_sel_signals [LAST_SIGNAL] = { 0 };
static void gnc_account_sel_init (GNCAccountSel *gas);
static void gnc_account_sel_class_init (GNCAccountSelClass *class);
static void gas_accounts_to_names( gpointer data, gpointer user_data );
static void gas_populate_list( GNCAccountSel *gas );
static void gas_strcmp_adapter( gpointer a, gpointer b );
static void gnc_account_sel_event_cb( GUID *entity,
GNCEngineEventType event_type,
gpointer user_data );
static void gas_new_account_click( GtkButton *b, gpointer ud );
static void gas_destroy( GtkObject *o, gpointer user_data );
#if 0 /* completion not implemented */
static void gnc_account_sel_changed( GtkEditable *entry, gpointer ud );
static void gnc_account_sel_list_clicked( GtkButton *b, gpointer ud );
static gint gnc_account_sel_key_press( GtkWidget *widget,
GdkEventKey *event );
#endif /* 0 -- completion not implemented */
static GtkHBox *parent_class;
guint
gnc_account_sel_get_type (void)
{
static guint account_sel_type = 0;
if (!account_sel_type){
GtkTypeInfo account_sel_info = {
"GNCAccountSel",
sizeof (GNCAccountSel),
sizeof (GNCAccountSelClass),
(GtkClassInitFunc) gnc_account_sel_class_init,
(GtkObjectInitFunc) gnc_account_sel_init,
NULL,
NULL,
(GtkClassInitFunc) NULL,
};
account_sel_type = gtk_type_unique (GTK_TYPE_HBOX, &account_sel_info);
}
return account_sel_type;
}
static
void
gnc_account_sel_event_cb( GUID *entity,
GNCEngineEventType event_type,
gpointer user_data )
{
if ( ! ( event_type == GNC_EVENT_CREATE
|| event_type == GNC_EVENT_MODIFY
|| event_type == GNC_EVENT_DESTROY )
|| strcmp( xaccGUIDType( entity,
gnc_get_current_book() ),
GNC_ID_ACCOUNT ) != 0 ) {
return;
}
gas_populate_list( (GNCAccountSel*)user_data );
}
static
void
gnc_account_sel_class_init (GNCAccountSelClass *class)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkHBoxClass *hbox_class;
object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
hbox_class = (GtkHBoxClass*) class;
parent_class = gtk_type_class (gtk_entry_get_type ());
account_sel_signals [ACCOUNT_SEL_CHANGED] =
gtk_signal_new ("account_sel_changed",
GTK_RUN_FIRST, object_class->type,
GTK_SIGNAL_OFFSET (GNCAccountSelClass,
account_sel_changed),
gtk_signal_default_marshaller,
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class,
account_sel_signals,
LAST_SIGNAL);
class->account_sel_changed = NULL;
}
static void
gnc_account_sel_init (GNCAccountSel *gas)
{
gas->initDone = FALSE;
gas->acctTypeFilters = FALSE;
gas->newAccountButton = NULL;
gas->combo = GTK_COMBO(gtk_combo_new());
gtk_combo_set_value_in_list( gas->combo, TRUE, TRUE );
gtk_container_add( GTK_CONTAINER(gas), GTK_WIDGET(gas->combo) );
/* This is only because completion cannot be implemented. */
gtk_editable_set_editable( GTK_EDITABLE(gas->combo->entry), FALSE );
gtk_signal_connect( GTK_OBJECT(gas), "destroy",
GTK_SIGNAL_FUNC( gas_destroy ),
gas );
#if 0 /* completion not implemented. */
gtk_signal_connect( GTK_OBJECT(gas->combo->entry), "changed",
GTK_SIGNAL_FUNC( gnc_account_sel_changed ),
gas );
#endif /* 0 -- completion not implemented. */
/* Get the accounts, place into combo list */
gas_populate_list( gas );
gas->eventHandlerId =
gnc_engine_register_event_handler( gnc_account_sel_event_cb, gas );
gas->initDone = TRUE;
}
typedef struct {
GNCAccountSel *gas;
GList **outList;
char accountSep;
} accounts_to_names_data;
/**
* Used in the g_list_foreach call in gas_populate_list to see if the given
* string is in [via strcmp] the list, and to set the flag as necessary.
**/
typedef struct {
char *str;
gboolean flag;
} findData;
static
void
gas_strcmp_adapter( gpointer listElt, gpointer ud )
{
findData *fd = (findData*)ud;
fd->flag |= ( strcmp( (char*)listElt, (char*)fd->str ) == 0 );
}
static
void
gas_populate_list( GNCAccountSel *gas )
{
accounts_to_names_data atnd;
AccountGroup *ag;
GList *accts, *nameList;
gchar *currentSel;
currentSel = gtk_editable_get_chars(
GTK_EDITABLE(gas->combo->entry), 0, -1 );
ag = gnc_book_get_group( gnc_get_current_book() );
accts = (GList*)xaccGroupGetSubAccounts( ag );
nameList = NULL;
atnd.gas = gas;
atnd.outList = &nameList;
atnd.accountSep = gnc_get_account_separator();
g_list_foreach( accts, gas_accounts_to_names,
(gpointer)&atnd );
g_list_free( accts );
if ( g_list_length( nameList ) > 0 ) {
gtk_combo_set_popdown_strings( gas->combo, nameList );
}
/* If the account which was in the text box before still exists, then
* reset to it. */
{
findData tmpfd;
gint pos;
tmpfd.str = currentSel;
tmpfd.flag = FALSE;
g_list_foreach( nameList, gas_strcmp_adapter, &tmpfd );
if ( tmpfd.flag ) {
gtk_editable_delete_text(
GTK_EDITABLE(gas->combo->entry), 0, -1 );
pos = 0;
gtk_editable_insert_text(
GTK_EDITABLE(gas->combo->entry),
currentSel, strlen(currentSel), &pos );
}
}
g_list_free( nameList );
if ( currentSel ) {
g_free( currentSel );
}
#if 0 /* completion not implemented */
gas->completion = g_completion_new( NULL );
g_completion_add_items( gas->completion, nameList );
#endif /* 0 -- completion not implemented */
}
static
void
gas_accounts_to_names( gpointer data, gpointer user_data )
{
accounts_to_names_data *atnd;
Account *a;
atnd = (accounts_to_names_data*)user_data;
a = (Account*)data;
/* Filter as we've been configured to do. */
if ( atnd->gas->acctTypeFilters ) {
/* g_list_find is the poor-mans '(member ...)', especially
* easy when the data pointers in the list are just casted
* account type identifiers. */
if ( g_list_find( atnd->gas->acctTypeFilters,
GINT_TO_POINTER(xaccAccountGetType( a )) )
== NULL ) {
return;
}
}
*atnd->outList =
g_list_append( *atnd->outList,
xaccAccountGetFullName(a, atnd->accountSep) );
}
#if 0 /* completion not implemented */
/*
* There is apparently no way -- in GTK 1.x -- to programatically select a
* region in the way we would like... so we've disallowed manual editing of
* the Account string.
*/
static
void
gnc_account_sel_changed( GtkEditable *entry, gpointer ud )
{
gchar *s, *prefix;
GNCAccountSel *gas = (GNCAccountSel*)ud;
if ( !gas->initDone ) {
return;
}
s = gtk_editable_get_chars( entry, 0, -1 );
g_completion_complete( gas->completion, s, &prefix );
if ( prefix && (strlen(prefix) > 0) ) {
printf( "changed into \"%s\"; longest completion: \"%s\"\n", s, prefix );
gtk_signal_handler_block_by_func( GTK_OBJECT(gas->combo->entry),
GTK_SIGNAL_FUNC(gnc_account_sel_changed),
ud );
gtk_entry_set_text( GTK_ENTRY(gas->combo->entry), prefix );
gtk_editable_select_region( GTK_EDITABLE(gas->combo->entry),
strlen(s), -1 );
{
GdkEventKey k;
gboolean ret;
k.type = GDK_KEY_RELEASE;
k.send_event = TRUE;
k.state = GDK_SHIFT_MASK;
k.keyval = GDK_End;
k.length = 0;
k.string = "";
printf( "foo [%d : \"%s\"]\n", k.length, k.string );
//gtk_widget_event( GTK_WIDGET(gas->combo->entry), &e );
gtk_signal_emit_by_name( GTK_OBJECT(gas->combo->entry),
"key-press-event",
gas->combo->entry, &k, NULL, &ret );
printf( "bar\n" );
}
gtk_editable_set_position( GTK_EDITABLE(gas->combo->entry),
strlen(s) );
gtk_signal_handler_unblock_by_func( GTK_OBJECT(gas->combo->entry),
GTK_SIGNAL_FUNC(gnc_account_sel_changed),
ud );
g_free( prefix );
}
g_free( s );
}
static
gint
gnc_account_sel_key_press(GtkWidget *widget, GdkEventKey *event)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(widget);
gint result;
result = (* GTK_WIDGET_CLASS (parent_class)->key_press_event)(widget, event);
switch (event->keyval)
{
case GDK_Tab:
/* FIXME: += equivalent keys. */
break;
if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SHIFT_MASK))
break;
return result;
case GDK_KP_Enter:
break;
default:
return result;
}
return TRUE;
}
#endif /* 0 -- completion not implemented */
GtkWidget *
gnc_account_sel_new (void)
{
GNCAccountSel *gas;
gas = gtk_type_new (gnc_account_sel_get_type ());
return GTK_WIDGET (gas);
}
GtkWidget *
gnc_account_sel_gtk_entry (GNCAccountSel *gas)
{
g_return_val_if_fail(gas != NULL, NULL);
g_return_val_if_fail(GNC_IS_ACCOUNT_SEL(gas), NULL);
return (GtkWidget *)gas->combo->entry;
}
void
gnc_account_sel_set_account( GNCAccountSel *gas, Account *acct )
{
gchar *acctStr;
if ( acct == NULL ) {
gtk_list_select_item( GTK_LIST(gas->combo->list), 0 );
return;
}
acctStr = xaccAccountGetFullName( acct,
gnc_get_account_separator() );
gtk_entry_set_text( GTK_ENTRY(gas->combo->entry), acctStr );
g_free( acctStr );
}
Account*
gnc_account_sel_get_account( GNCAccountSel *gas )
{
AccountGroup *ag;
Account *ret;
gchar *txt;
ret = NULL;
txt = gtk_editable_get_chars( GTK_EDITABLE(gas->combo->entry), 0, -1 );
g_assert( txt != NULL );
if ( strlen(txt) == 0 ) {
goto cleanup;
}
ag = gnc_book_get_group( gnc_get_current_book() );
ret = xaccGetAccountFromFullName( ag, txt, gnc_get_account_separator() );
cleanup:
g_free( txt );
return ret;
}
void
gnc_account_sel_set_acct_filters( GNCAccountSel *gas, GList *filters )
{
if ( gas->acctTypeFilters != NULL ) {
g_list_free( gas->acctTypeFilters );
gas->acctTypeFilters = NULL;
}
/* If it's null, then no filters exist. */
if ( ! filters ) {
return;
}
/* This works because the GNCAccountTypes in the list are
* ints-casted-as-pointers. */
gas->acctTypeFilters = g_list_copy( filters );
gas_populate_list( gas );
}
static
void
gas_destroy( GtkObject *o, gpointer user_data )
{
GNCAccountSel *gas = (GNCAccountSel*)user_data;
if ( gas->acctTypeFilters ) {
g_list_free( gas->acctTypeFilters );
}
gnc_engine_unregister_event_handler( gas->eventHandlerId );
}
void
gnc_account_sel_set_new_account_ability( GNCAccountSel *gas,
gboolean state )
{
g_assert( gas );
if ( state == (gas->newAccountButton != NULL) ) {
/* We're already in that state; don't do anything. */
return;
}
if ( gas->newAccountButton ) {
g_assert( state == TRUE );
/* destroy the existing button. */
gtk_container_remove( GTK_CONTAINER(gas),
gas->newAccountButton );
gtk_widget_destroy( gas->newAccountButton );
gas->newAccountButton = NULL;
return;
}
/* create the button. */
gas->newAccountButton = gtk_button_new_with_label( _("New...") );
gtk_signal_connect( GTK_OBJECT(gas->newAccountButton),
"clicked",
GTK_SIGNAL_FUNC( gas_new_account_click ),
gas );
gtk_box_pack_start( GTK_BOX(gas), gas->newAccountButton,
FALSE, FALSE, 2 );
}
static
void
gas_new_account_click( GtkButton *b, gpointer ud )
{
GNCAccountSel *gas = (GNCAccountSel*)ud;
gnc_ui_new_account_with_types( NULL, gas->acctTypeFilters );
}
@@ -1,11 +1,15 @@
/**
* gnc-account-sel.h -- combobox style account selection widget, with
* auto-completion.
* gnc-account-sel.h -- combobox style account selection widget.
*
* Note that this widget will track changes in the account tree, and update
* itself accordingly. If an account with the same name exists in the
* freshly-retreived account list, the widget will re-select that account.
*
* Copyright (C) 2002 Joshua Sled <jsled@asynchronous.org>
* All rights reserved.
*
* GnuCash is free software; you can redistribute it and/or modify
**/
/* GnuCash is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
@@ -21,7 +25,7 @@
* Free Software Foundation Voice: +1-617-542-5942
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652
* Boston, MA 02111-1307, USA gnu@gnu.org
**/
*/
#ifndef GNC_ACCOUNT_SEL_H
#define GNC_ACCOUNT_SEL_H
@@ -37,18 +41,26 @@ BEGIN_GNOME_DECLS
typedef struct
{
GtkHBox hbox;
gboolean initDone;
GtkCombo *combo;
GCompletion *completion;
GtkHBox hbox;
gboolean initDone;
GtkCombo *combo;
GList *acctTypeFilters;
gint eventHandlerId;
/* The state of this pointer also serves as a flag about what state
* the widget is in WRT the new-account-button ability. */
GtkWidget *newAccountButton;
#if 0 /* completion not implemented. */
GCompletion *completion;
#endif /* 0 - completion not implemented */
} GNCAccountSel;
typedef struct
{
GtkHBoxClass parent_class;
GtkHBoxClass parent_class;
/* Signals for notification/filtering of changes */
void (*account_sel_changed) (GNCAccountSel *gas);
/* Signals for notification/filtering of changes */
void (*account_sel_changed) (GNCAccountSel *gas);
} GNCAccountSelClass;
guint gnc_account_sel_get_type(void);
@@ -66,6 +78,21 @@ void gnc_account_sel_set_account( GNCAccountSel *gas, Account *acct );
**/
Account* gnc_account_sel_get_account( GNCAccountSel *gas );
/**
* The GNCAccountSel can be setup to filter the accounts displayed.
* @param filters A GList of GNCAccountType identifiers which are allowed.
* The list is copied, of course.
**/
void gnc_account_sel_set_acct_filters( GNCAccountSel *gas, GList *filters );
/**
* Conditional inclusion of a new-account button to the right of the
* combobox.
* @param state TRUE if the new-account button is desired, FALSE otherwise.
**/
void gnc_account_sel_set_new_account_ability( GNCAccountSel *gas,
gboolean state );
END_GNOME_DECLS
#endif /* !ndef GNC_ACCOUNT_SEL_H */
+1 -1
View File
@@ -852,7 +852,7 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
static GnomeUIInfo gnc_sched_xaction_tools_submenu_template[] =
{
{ GNOME_APP_UI_ITEM,
N_("_List and Editor"),
N_("_Scheduled Transaction Editor"),
N_("The list of Scheduled Transactions"),
gnc_main_window_sched_xaction_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,