From e19df01f5fc9096302f09f46ca4711c2ef3ec4be Mon Sep 17 00:00:00 2001 From: Joshua Sled Date: Thu, 11 Mar 2004 01:17:14 +0000 Subject: [PATCH] 2004-03-07 Joshua Sled * HACKING: Added instructions about running under valgrind. * lib/gnucash_valgrind.supp: Added a large set of valgrind suppressions for both guile and gnucash. * src/register/ledger-core/gnc-ledger-display.c (gnc_ledger_display_template_gl): Change the reg_type to SEARCH_LEDGER so all the 'action' types appear. Bug#108833. * src/gnome/glade/sched-xact.glade: Remove unused 'ledger_status' widget. Bug#102269. * src/gnome-utils/gnc-dense-cal.c (gnc_dense_cal_draw_to_buffer): At least be consistent about the background coloring of the month labels, even if we're still not using GTK themeage correctly. * src/gnome-utils/gnc-dense-cal.c (gnc_dense_cal_destroy): Destroy the transient window when the widget is destroyed. Bug#103910. * src/gnome/dialog-scheduledxaction.c (gnc_ui_scheduled_xaction_editor_dialog_create): Make the advance and remind spin-buttons editable [Bug#94963]. * src/gnome/glade/sched-xact.glade: Change the upper bound on the advance and remind spins to 365 [days], with a page-size of 30 [days]. * src/gnome/dialog-sx-from-trans.c (gnc_sx_create_from_trans): Disallow the Scheduling of being-editing transactions in the Register, preventing a class of unbalacned SX template transactions from being entered and propogated through the system. See Bug#130330. * src/engine/FreqSpec.c (xaccFreqSpecGetFreqStr): Fix nasty memory-corruption issue; insufficent bounds checking on array index. Bug#125600. * src/gnome/dialog-sxsincelast.c (create_each_transaction_helper): Better handling of various error cases in transaction-creation. Bug#120311; Bug#130330. 2004-03-01 Joshua Sled * src/gnome/dialog-scheduledxaction.c (gnc_sxed_check_consistent): Fix for part of Bug#121740 -- only allow auto-create SXes which have splits to be created. 2004-02-07 Joshua Sled * src/gnome/dialog-scheduledxaction.c (editor_ok_button_clicked): * src/gnome-utils/gnc-frequency.c (gnc_frequency_save_state): * src/backend/file/gnc-freqspec-xml-v2.c (fs_none_handler): * src/engine/FreqSpec.c (xaccFreqSpecGetFreqStr): Adding "NONE" as an allowable FreqSpec [Bug#103968]. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@9858 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 57 +++++++ HACKING | 12 +- Makefile.am | 2 +- src/backend/file/gnc-freqspec-xml-v2.c | 23 ++- src/doc/TODO-schedxactions | 9 ++ src/engine/FreqSpec.c | 19 ++- src/engine/FreqSpec.h | 2 + src/gnome-utils/gnc-dense-cal.c | 24 ++- src/gnome/dialog-scheduledxaction.c | 153 +++++++++++++----- src/gnome/dialog-sx-from-trans.c | 66 +++++++- src/gnome/glade/sched-xact.glade | 21 +-- src/register/ledger-core/gnc-ledger-display.c | 2 +- 12 files changed, 321 insertions(+), 69 deletions(-) diff --git a/ChangeLog b/ChangeLog index 535df35658..2db52b76a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,49 @@ glade/hbci.glade, gnc-hbci-transfer.c: Transfer template management GUI added by Bernd Wagner +2004-03-07 Joshua Sled + + * HACKING: Added instructions about running under valgrind. + + * lib/gnucash_valgrind.supp: Added a large set of valgrind + suppressions for both guile and gnucash. + + * src/register/ledger-core/gnc-ledger-display.c + (gnc_ledger_display_template_gl): Change the reg_type to + SEARCH_LEDGER so all the 'action' types appear. Bug#108833. + + * src/gnome/glade/sched-xact.glade: Remove unused 'ledger_status' + widget. Bug#102269. + + * src/gnome-utils/gnc-dense-cal.c (gnc_dense_cal_draw_to_buffer): + At least be consistent about the background coloring of the month + labels, even if we're still not using GTK themeage correctly. + + * src/gnome-utils/gnc-dense-cal.c (gnc_dense_cal_destroy): Destroy + the transient window when the widget is destroyed. Bug#103910. + + * src/gnome/dialog-scheduledxaction.c + (gnc_ui_scheduled_xaction_editor_dialog_create): Make the advance + and remind spin-buttons editable [Bug#94963]. + + * src/gnome/glade/sched-xact.glade: Change the upper bound on the + advance and remind spins to 365 [days], with a page-size of 30 + [days]. + + * src/gnome/dialog-sx-from-trans.c (gnc_sx_create_from_trans): + Disallow the Scheduling of being-editing transactions in the + Register, preventing a class of unbalacned SX template + transactions from being entered and propogated through the + system. See Bug#130330. + + * src/engine/FreqSpec.c (xaccFreqSpecGetFreqStr): Fix nasty + memory-corruption issue; insufficent bounds checking on array + index. Bug#125600. + + * src/gnome/dialog-sxsincelast.c (create_each_transaction_helper): + Better handling of various error cases in + transaction-creation. Bug#120311; Bug#130330. + 2004-03-03 Derek Atkins * src/register/ledger-core/split-register-load.c: make the code a @@ -12,6 +55,20 @@ existing variable. Unlikely to actually fix anything, but you never know what a compiler might do. +2004-03-01 Joshua Sled + + * src/gnome/dialog-scheduledxaction.c (gnc_sxed_check_consistent): + Fix for part of Bug#121740 -- only allow auto-create SXes which + have splits to be created. + +2004-02-07 Joshua Sled + + * src/gnome/dialog-scheduledxaction.c (editor_ok_button_clicked): + * src/gnome-utils/gnc-frequency.c (gnc_frequency_save_state): + * src/backend/file/gnc-freqspec-xml-v2.c (fs_none_handler): + * src/engine/FreqSpec.c (xaccFreqSpecGetFreqStr): + Adding "NONE" as an allowable FreqSpec [Bug#103968]. + 2004-02-14 Christian Stimming * configure.in: Require the correct openhbci2 version. Add verbose diff --git a/HACKING b/HACKING index b8ad93d5f1..0094e150bd 100644 --- a/HACKING +++ b/HACKING @@ -129,4 +129,14 @@ However, I did not find valgrind to be useful. It reported a bunch of guile bugs, some g_has_table bugs, and then the program exited prematurely for no appearenet reason. :-( -If you know how to fix this, please update tehse instructions. +For the moment, use the supressions in lib/gnucash_valgrind.supp. + +This file needs to be cleaned up in two ways: + +1/ There are a bunch of duplicate supressions in the file. + * The supressions in place were auto-generated by valgrind itself + [--gen-suppressions=yes], and it makes no effort to output the + suppression only once. + +2/ There are a bunch of suppressions which need to not be supressions, but + instead just not be generated by valgrind. diff --git a/Makefile.am b/Makefile.am index fe8460b0bd..188d3d3c55 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,7 +33,7 @@ m4data_DATA = gnucash.m4 # Don't list any directories or you'll get *everything*, including the # CVS dirs. -EXTRA_DIST = config.rpath \ +EXTRA_DIST = config.rpath config.rpath \ .cvsignore \ ChangeLog.1 \ HACKING \ diff --git a/src/backend/file/gnc-freqspec-xml-v2.c b/src/backend/file/gnc-freqspec-xml-v2.c index b2a4634198..79596d5f0a 100644 --- a/src/backend/file/gnc-freqspec-xml-v2.c +++ b/src/backend/file/gnc-freqspec-xml-v2.c @@ -86,6 +86,7 @@ struct freqTypeTuple { }; struct freqTypeTuple freqTypeStrs[] = { + { "none", INVALID }, { "once", ONCE }, { "daily", DAILY }, { "weekly", WEEKLY }, @@ -163,6 +164,11 @@ gnc_freqSpec_dom_tree_create( FreqSpec *fs ) xmlAddChild( ret, xmlSub ); switch( fs->type ) { + + case INVALID: { + xmlSub = xmlNewNode( NULL, "fs:none" ); + } break; + case ONCE: { xmlSub = xmlNewNode( NULL, "fs:once" ); xmlAddChild( xmlSub, @@ -260,7 +266,6 @@ gnc_freqSpec_dom_tree_create( FreqSpec *fs ) xmlAddChild( ret, xmlComposites ); } break; - case INVALID: default: g_return_val_if_fail( FALSE, NULL ); } @@ -412,6 +417,21 @@ struct dom_tree_handler fs_union_dom_handlers[] = { { NULL, NULL, 0, 0 }, }; +static +gboolean +fs_none_handler( xmlNodePtr node, gpointer data ) +{ + fsParseData *fspd = data; + gboolean successful; + successful = dom_tree_generic_parse( node, + fs_union_dom_handlers, + fspd ); + if ( !successful ) + return FALSE; + fspd->fs->type = INVALID; + return TRUE; +} + static gboolean fs_once_handler( xmlNodePtr node, gpointer data ) @@ -531,6 +551,7 @@ static struct dom_tree_handler fs_dom_handlers[] = { { "gnc:freqspec", gnc_fs_handler, 0, 0 }, { "fs:ui_type", fs_uift_handler, 1, 0 }, { "fs:id", fs_guid_handler, 1, 0 }, + { "fs:none", fs_none_handler, 0, 0 }, { "fs:once", fs_once_handler, 0, 0 }, { "fs:daily", fs_daily_handler, 0, 0 }, { "fs:weekly", fs_weekly_handler, 0, 0 }, diff --git a/src/doc/TODO-schedxactions b/src/doc/TODO-schedxactions index 74ab34ca96..0a0e21345f 100644 --- a/src/doc/TODO-schedxactions +++ b/src/doc/TODO-schedxactions @@ -3,6 +3,15 @@ Author: jsled@asynchronous.org Main Scheduled Transaction todo list ------------------------------------ +. Bug#102311... + + . As per comment 2004-01-05T16:31, there is an issue when other pieces of + the system change accounts that SXes depend on. We have two options: + 1: handle change at account-deletion time ["remove this acocunt will + affect this scheduled transaction ... what to do?"] + 2: break out of SX since-last-run processing ["this account was removed; + {edit,delete} SX?"]. + ################################################## ### To-Do ### diff --git a/src/engine/FreqSpec.c b/src/engine/FreqSpec.c index 5e6d8a0137..e80f3ea0fd 100644 --- a/src/engine/FreqSpec.c +++ b/src/engine/FreqSpec.c @@ -138,6 +138,7 @@ get_wday_name(guint day) { static gchar wday_name[WDAY_BUF_WIDTH]; struct tm t; + memset( &t, 0, sizeof( t ) ); t.tm_wday = day; strftime(wday_name, WDAY_NAME_WIDTH, "%A", &t); return wday_name; @@ -160,6 +161,7 @@ get_abbrev_month_name(guint month) { static gchar month_name[WDAY_BUF_WIDTH]; struct tm t; + memset( &t, 0, sizeof( t ) ); t.tm_mon = month; strftime(month_name, WDAY_NAME_WIDTH, "%b", &t); return month_name; @@ -240,7 +242,7 @@ xaccFreqSpecGetType( FreqSpec *fs ) { g_return_val_if_fail( fs, INVALID ); /* Is this really a fail? */ - g_return_val_if_fail( fs->type != INVALID, INVALID ); + //g_return_val_if_fail( fs->type != INVALID, INVALID ); return fs->type; } @@ -451,6 +453,14 @@ xaccFreqSpecIsValidDateRelaxed( FreqSpec *fs, time_t query ) } */ +void +xaccFreqSpecSetNone( FreqSpec *fs ) +{ + g_return_if_fail( fs ); + xaccFreqSpecCleanUp( fs ); + fs->type = INVALID; +} + void xaccFreqSpecSetOnceDate( FreqSpec *fs, const GDate* when ) { @@ -709,6 +719,10 @@ xaccFreqSpecGetFreqStr( FreqSpec *fs, GString *str ) memset( freqStrBuf, 0, MAX_FREQ_STR_SIZE + 1 ); switch( xaccFreqSpecGetUIType( fs ) ) { + case UIFREQ_NONE: + snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, _("None") ); + break; + case UIFREQ_ONCE: tmpStr = g_new0( char, GDATE_STRING_BUF_SIZE ); /* this is now a GDate. */ @@ -778,6 +792,7 @@ xaccFreqSpecGetFreqStr( FreqSpec *fs, GString *str ) if ( xaccFreqSpecGetType(tmpFS) != WEEKLY ) { snprintf( freqStrBuf, MAX_FREQ_STR_SIZE, "error: UIFREQ_WEEKLY doesn't contain weekly children" ); + g_free( tmpStr ); return; } if ( tmpInt == -1 ) { @@ -785,7 +800,7 @@ xaccFreqSpecGetFreqStr( FreqSpec *fs, GString *str ) } /* put the first letter of the weekday name in the appropriate position. */ - dowIdx = tmpFS->s.weekly.offset_from_epoch; + dowIdx = tmpFS->s.weekly.offset_from_epoch % 7; tmpStr[dowIdx] = *(get_wday_name(dowIdx)); } diff --git a/src/engine/FreqSpec.h b/src/engine/FreqSpec.h index 7973df31d4..0bf4bac045 100644 --- a/src/engine/FreqSpec.h +++ b/src/engine/FreqSpec.h @@ -126,6 +126,8 @@ void xaccFreqSpecSetUIType( FreqSpec *fs, UIFreqType newUIFreqType ); UIFreqType xaccFreqSpecGetUIType( FreqSpec *fs ); +void xaccFreqSpecSetNone( FreqSpec *fs ); + /** * Sets the type to once-off, and initialises the * date it occurs on. diff --git a/src/gnome-utils/gnc-dense-cal.c b/src/gnome-utils/gnc-dense-cal.c index 85c8317d17..79c378c1db 100644 --- a/src/gnome-utils/gnc-dense-cal.c +++ b/src/gnome-utils/gnc-dense-cal.c @@ -171,6 +171,8 @@ static const gchar *month_name(int mon) struct tm my_tm; int i; + memset( buf, 0, MONTH_NAME_BUFSIZE ); + memset( &my_tm, 0, sizeof( struct tm ) ); my_tm.tm_mon = mon; i = strftime (buf, MONTH_NAME_BUFSIZE-1, "%b", &my_tm); return buf; @@ -187,6 +189,8 @@ static const gchar *day_label(int wday) struct tm my_tm; int i; + memset( buf, 0, MONTH_NAME_BUFSIZE ); + memset( &my_tm, 0, sizeof( struct tm ) ); my_tm.tm_wday = wday; i = strftime (buf, MONTH_NAME_BUFSIZE-1, "%a", &my_tm); /* Wild hack to use only the first two letters */ @@ -467,6 +471,13 @@ gnc_dense_cal_destroy (GtkObject *object) g_return_if_fail (GNC_IS_DENSE_CAL (object)); dcal = GNC_DENSE_CAL(object); + + if ( GTK_WIDGET_REALIZED( dcal->transPopup ) ) { + gtk_widget_hide( GTK_WIDGET(dcal->transPopup) ); + gtk_widget_destroy( GTK_WIDGET(dcal->transPopup) ); + dcal->transPopup = NULL; + } + if ( dcal->drawbuf ) gdk_pixmap_unref( dcal->drawbuf ); @@ -762,13 +773,13 @@ gnc_dense_cal_draw_to_buffer( GncDenseCal *dcal ) dcal->label_width, dcal->label_height, -1 ); gdk_draw_rectangle( dcal->monthLabels[i], - widget->style->bg_gc[widget->state], + widget->style->white_gc, TRUE, 0, 0, dcal->label_width, dcal->label_height ); gdk_draw_rectangle( tmpPix, - widget->style->bg_gc[widget->state], + widget->style->white_gc, TRUE, 0, 0, dcal->label_height, dcal->label_width ); @@ -783,7 +794,7 @@ gnc_dense_cal_draw_to_buffer( GncDenseCal *dcal ) dcal->label_width ); /* now, (transpose the pixel matrix)==(do a 90-degree - * counter-clocwise rotation) */ + * counter-clockwise rotation) */ for ( x=0; x < dcal->label_height; x++ ) { for ( y=0; y < dcal->label_width; y++ ) { if ( gdk_image_get_pixel( tmpImg, x, y ) @@ -955,7 +966,7 @@ gnc_dense_cal_draw_to_buffer( GncDenseCal *dcal ) g_date_add_days( &d, 1 ), doc++ ) { doc_coords( dcal, doc, &x1, &y1, &x2, &y2 ); memset( dayNumBuf, 0, 3 ); - sprintf( dayNumBuf, "%d", g_date_day( &d ) ); + snprintf( dayNumBuf, 3, "%d", g_date_day( &d ) ); numW = gdk_string_width( dcal->dayLabelFont, dayNumBuf ); numH = gdk_string_height( dcal->dayLabelFont, dayNumBuf ); w = (x2 - x1)+1; @@ -1018,6 +1029,8 @@ populate_hover_window( GncDenseCal *dcal, gint doc ) rowText[1] = gdcmd->info; gtk_clist_insert( cl, row++, rowText ); } + + // FIXME: free 'date'? } } @@ -1221,6 +1234,7 @@ month_coords( GncDenseCal *dcal, int monthOfCal, GList **outList ) startD = g_date_new(); endD = g_date_new(); + // FIXME: clean these up? /* Calculate the number of weeks in the column before the month we're * interested in. */ @@ -1549,6 +1563,7 @@ gnc_dense_cal_mark_remove( GncDenseCal *dcal, guint markToRemove ) /* Ignore non-realistic marks */ if ( (gint)markToRemove == -1 ) { + DEBUG( "markToRemove = -1" ); return; } @@ -1560,6 +1575,7 @@ gnc_dense_cal_mark_remove( GncDenseCal *dcal, guint markToRemove ) } g_assert( l != NULL ); if ( l == NULL ) { + DEBUG( "l == null" ); return; } g_assert( gdcmd != NULL ); diff --git a/src/gnome/dialog-scheduledxaction.c b/src/gnome/dialog-scheduledxaction.c index d231b09550..991f768bf9 100644 --- a/src/gnome/dialog-scheduledxaction.c +++ b/src/gnome/dialog-scheduledxaction.c @@ -102,6 +102,16 @@ typedef enum _EndTypeEnum { 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; @@ -212,6 +222,10 @@ 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 ); + + /** Implementations *****************************************************/ static @@ -224,6 +238,15 @@ sxd_close_handler ( gpointer user_data ) gnome_dialog_close( GNOME_DIALOG( 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 ) { @@ -233,9 +256,13 @@ gnc_sxd_list_refresh( SchedXactionDialog *sxd ) /* 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 ); } @@ -342,9 +369,10 @@ editor_ok_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed ) sxList = gnc_book_get_schedxactions( book ); sxList = g_list_append( sxList, sxed->sx ); gnc_book_set_schedxactions( book, sxList ); - sxed->sx = NULL; sxed->newsxP = FALSE; } + // regardless, do this so the close handler won't complain. + sxed->sx = NULL; /* update lists */ /* We now do this by getting the list of SX Lists and updating them @@ -607,7 +635,7 @@ static gboolean gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed ) { - gint ttVarCount; + gint ttVarCount, splitCount; FreqSpec *fs; /* Do checks on validity and such, interrupting the user if @@ -630,6 +658,7 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed ) */ ttVarCount = 0; + splitCount = 0; { static const int NUM_ITERS_WITH_VARS = 5; static const int NUM_ITERS_NO_VARS = 1; @@ -685,8 +714,11 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed ) (gpointer)vars ); g_hash_table_foreach( txns, set_sums_to_zero, NULL ); tmp = gnc_numeric_zero(); - for ( splitList = xaccSchedXactionGetSplits( sxed->sx ); - splitList; splitList = splitList->next ) + + splitList = xaccSchedXactionGetSplits( sxed->sx ); + splitCount += g_list_length( splitList ); + + for ( ; splitList; splitList = splitList->next ) { txnCreditDebitSums *tcds; s = (Split*)splitList->data; @@ -835,6 +867,15 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed ) "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\n" + "transaction cannot be automatically created.") ); + return FALSE; + } } /* deal with time. */ @@ -1004,6 +1045,10 @@ gnc_sxed_save_sx( SchedXactionEditorDialog *sxed ) fs = xaccSchedXactionGetFreqSpec( sxed->sx ); gnc_frequency_save_state( sxed->gncfreq, fs, &gdate ); + GString *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 ); } @@ -1049,6 +1094,8 @@ scheduledxaction_dialog_destroy(GtkObject *object, gpointer data) gnc_unregister_gui_component_by_data (DIALOG_SCHEDXACTION_CM_CLASS, sxd); + // FIXME: um. We should free memory and stuff, here. + g_free( sxd ); } @@ -1144,6 +1191,8 @@ gnc_ui_scheduled_xaction_dialog_create(void) gtk_signal_connect( GTK_OBJECT(w), "click-column", GTK_SIGNAL_FUNC(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; @@ -1400,6 +1449,10 @@ gnc_ui_scheduled_xaction_editor_dialog_create( SchedXactionDialog *sxd, gtk_widget_set_sensitive( GTK_WIDGET(sxed->remindSpin), FALSE ); gtk_widget_set_sensitive( GTK_WIDGET(sxed->endCountEntry), FALSE ); gtk_widget_set_sensitive( GTK_WIDGET(sxed->endRemainEntry), FALSE ); + + gtk_editable_set_editable( GTK_EDITABLE(sxed->advanceSpin), TRUE ); + gtk_editable_set_editable( GTK_EDITABLE(sxed->remindSpin), TRUE ); + /* Allow grow, allow shrink, auto-shrink */ gtk_window_set_policy (GTK_WINDOW(sxed->dialog), TRUE, TRUE, FALSE); @@ -1795,18 +1848,19 @@ delete_button_clicked( GtkButton *b, gpointer d ) book = gnc_get_current_book (); sxList = gnc_book_get_schedxactions( book ); for ( sel = cl->selection; sel; sel = sel->next ) { - gint tag; - gint *p_tag = &tag; + SxRuntimeInfo *sxri; + SxRuntimeInfo **p_sxri = &sxri; gpointer unused; gboolean foundP; sx = (SchedXaction*)gtk_clist_get_row_data( cl, (int)sel->data ); sxList = g_list_remove( sxList, (gpointer)sx ); foundP = g_hash_table_lookup_extended( sxd->sxData, sx, - &unused, (gpointer*)p_tag ); + &unused, + (gpointer*)p_sxri ); g_assert( foundP ); - if ( tag != -1 ) { - gnc_dense_cal_mark_remove( sxd->gdcal, tag ); + if ( sxri->markTag != -1 ) { + gnc_dense_cal_mark_remove( sxd->gdcal, sxri->markTag ); } g_hash_table_remove( sxd->sxData, sx ); xaccSchedXactionFree( sx ); @@ -1898,6 +1952,19 @@ _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 ) @@ -1908,14 +1975,17 @@ putSchedXactionInDialog( gpointer data, gpointer user_data ) char *text[3]; GString *freqStr; GString *nextDate; - gint row; int i; GDate *nextInstDate = NULL, *calEndDate; int instArraySize; GDate **instArray; GList *instList; - gint gdcMarkTag, oldMarkTag; - gint *p_oldMarkTag = &oldMarkTag; + gpointer unused; + SxRuntimeInfo *sxri = NULL; + SxRuntimeInfo **p_sxri = &sxri; + gboolean foundP; + gint gdcMarkTag; + gint row; sx = (SchedXaction*)data; sxd = (SchedXactionDialog*)user_data; @@ -1986,38 +2056,47 @@ putSchedXactionInDialog( gpointer data, gpointer user_data ) 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, sx ); - if ( row != -1 ) { - gpointer unused; - gboolean foundP = - g_hash_table_lookup_extended( sxd->sxData, - (gpointer)sx, - &unused, - (gpointer*)p_oldMarkTag ); - g_assert( foundP ); - } - if ( row == -1 ) { + + row = gtk_clist_find_row_from_data( clist, (gpointer)sx ); + if ( sxri->row == -1 ) { /* new item to be inserted */ - row = gtk_clist_append( clist, text ); - gtk_clist_set_row_data( clist, row, sx ); + sxri->row = gtk_clist_append( clist, text ); + gtk_clist_set_row_data( clist, sxri->row, sx ); } else { - /* old item being replaced. */ - if ( oldMarkTag != -1 ) { - gnc_dense_cal_mark_remove( sxd->gdcal, oldMarkTag ); - } for ( i=0; i<3; i++ ) { - gtk_clist_set_text( clist, row, i, text[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)gdcMarkTag ); + g_hash_table_insert( sxd->sxData, (gpointer)sx, (gpointer)sxri ); + sxri = NULL; g_string_free( freqStr, TRUE ); g_string_free( nextDate, TRUE ); @@ -2272,10 +2351,8 @@ gnc_sxed_update_cal( SchedXactionEditorDialog *sxed ) } i = 0; - gnc_dense_cal_set_month( sxed->example_cal, - g_date_month( &d ) ); - gnc_dense_cal_set_year( sxed->example_cal, - g_date_year( &d ) ); + gnc_dense_cal_set_month( sxed->example_cal, g_date_month( &d ) ); + gnc_dense_cal_set_year( sxed->example_cal, g_date_year( &d ) ); while ( (i < EX_CAL_NUM_MONTHS * 31) && g_date_valid( &d ) /* Restrict based on end date */ @@ -2307,8 +2384,12 @@ gnc_sxed_update_cal( SchedXactionEditorDialog *sxed ) sxed->cal_marks, name, info->str ); gtk_widget_queue_draw( GTK_WIDGET( sxed->example_cal ) ); - g_free( name ); + g_string_free( info, TRUE ); + if ( name != NULL ) + { + g_free( name ); + } } xaccFreqSpecFree( fs ); diff --git a/src/gnome/dialog-sx-from-trans.c b/src/gnome/dialog-sx-from-trans.c index 56632dcc8b..25489f3b57 100644 --- a/src/gnome/dialog-sx-from-trans.c +++ b/src/gnome/dialog-sx-from-trans.c @@ -38,6 +38,7 @@ #include "gnc-book.h" #include "gnc-date-edit.h" #include "gnc-engine-util.h" +#include "gnc-ui.h" #include "gnc-ui-util.h" #include "gnc-dense-cal.h" @@ -60,6 +61,9 @@ #define SX_OPT_STR "Scheduled Transactions" +#define SXFTD_ERRNO_UNBALANCED_XACTION 3 +#define SXFTD_ERRNO_OPEN_XACTION -3 + #define SXFTD_EXCAL_NUM_MONTHS 4 #define SXFTD_EXCAL_MONTHS_PER_COL 4 @@ -212,14 +216,17 @@ sxftd_add_template_trans(SXFromTransInfo *sxfti) { Transaction *tr = sxfti->trans; - GList *tt_list= NULL; + GList *tt_list = NULL; GList *splits, *template_splits = NULL; TTInfo *tti = gnc_ttinfo_malloc(); TTSplitInfo *ttsi; Split *sp; + gnc_numeric runningBalance; gnc_numeric split_value; const char *tmpStr; + runningBalance = gnc_numeric_zero(); + gnc_ttinfo_set_description(tti, xaccTransGetDescription(tr)); gnc_ttinfo_set_num(tti, xaccTransGetNum(tr)); gnc_ttinfo_set_currency(tti, xaccTransGetCurrency(tr)); @@ -232,6 +239,9 @@ sxftd_add_template_trans(SXFromTransInfo *sxfti) split_value = xaccSplitGetValue(sp); gnc_ttsplitinfo_set_memo(ttsi, xaccSplitGetMemo(sp)); + runningBalance = gnc_numeric_add( runningBalance, split_value, + 100, (GNC_DENOM_AUTO | GNC_DENOM_LCD) ); + if(gnc_numeric_positive_p(split_value)) { tmpStr = xaccPrintAmount( split_value, @@ -252,6 +262,17 @@ sxftd_add_template_trans(SXFromTransInfo *sxfti) template_splits = g_list_append(template_splits, ttsi); } + if ( ! gnc_numeric_zero_p( runningBalance ) + && !gnc_verify_dialog( (gncUIWidget)sxfti->dialog, + FALSE, "%s", + _("The Scheduled Transaction Editor " + "cannot automatically\nbalance " + "this transaction. " + "Should it still be " + "entered?") ) ) { + return SXFTD_ERRNO_UNBALANCED_XACTION; + } + gnc_ttinfo_set_template_splits(tti, template_splits); tt_list = g_list_append(tt_list, tti); @@ -338,7 +359,10 @@ sxftd_init( SXFromTransInfo *sxfti ) if ( ! sxfti->trans ) { return -2; } - + if ( xaccTransIsOpen( sxfti->trans ) ) { + return SXFTD_ERRNO_OPEN_XACTION; + } + sxfti_attach_callbacks(sxfti); /* Setup the example calendar and related data structures. */ @@ -512,7 +536,10 @@ sxftd_compute_sx(SXFromTransInfo *sxfti) xaccSchedXactionSetAdvanceReminder( sx, daysInAdvance ); } - sxftd_add_template_trans( sxfti ); + if ( sxftd_add_template_trans( sxfti ) != 0 ) + { + sxftd_errno = SXFTD_ERRNO_UNBALANCED_XACTION; + } return sxftd_errno; } @@ -540,13 +567,20 @@ sxftd_ok_clicked(GtkWidget *w, gpointer user_data) GList *sx_list; guint sx_error = sxftd_compute_sx(sxfti); - if (sx_error != 0) + if (sx_error != 0 + && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION) { 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.\n" + "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); @@ -609,10 +643,13 @@ sxftd_advanced_clicked(GtkWidget *w, gpointer user_data) SchedXactionDialog *adv_dlg; SchedXactionEditorDialog *adv_edit_dlg; - if (sx_error != 0) + if ( sx_error != 0 + && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION ) { - PWARN( "something bad happened in sxftd_compute_sx [%d]", sx_error ); - return; + // unbalanced-xaction is "okay", since this is also checked for by + // the advanced editor. + PWARN( "something bad happened in sxftd_compute_sx [%d]", sx_error ); + return; } gtk_widget_hide( sxfti->dialog ); /* force a gui update. */ @@ -645,7 +682,20 @@ gnc_sx_create_from_trans( Transaction *trans ) sxfti->sx = xaccSchedXactionMalloc(gnc_get_current_book ()); if ( (errno = sxftd_init( sxfti )) < 0 ) { - PERR( "Error in sxftd_init: %d", errno ); + if ( errno == SXFTD_ERRNO_OPEN_XACTION ) + { + gnc_error_dialog( gnc_ui_get_toplevel(), + _( "Cannot create a Scheduled Transaction " + "from a Transaction currently\n" + "being edited. Please Enter the " + "Transaction before Scheduling." ) ); + sxftd_close( sxfti, TRUE ); + return; + } + else + { + PERR( "Error in sxftd_init: %d", errno ); + } } gtk_widget_show_all(sxfti->dialog); diff --git a/src/gnome/glade/sched-xact.glade b/src/gnome/glade/sched-xact.glade index 777e6fbd42..95fef393a8 100644 --- a/src/gnome/glade/sched-xact.glade +++ b/src/gnome/glade/sched-xact.glade @@ -313,10 +313,10 @@ False 0 0 - 100 + 365 1 - 10 - 10 + 30 + 30 0 False @@ -390,10 +390,10 @@ False 0 0 - 100 + 365 1 - 10 - 10 + 30 + 30 0 False @@ -696,15 +696,6 @@ - - GtkStatusbar - ledger_status - - 0 - False - False - - diff --git a/src/register/ledger-core/gnc-ledger-display.c b/src/register/ledger-core/gnc-ledger-display.c index 96cbfcb295..8d951c5f56 100644 --- a/src/register/ledger-core/gnc-ledger-display.c +++ b/src/register/ledger-core/gnc-ledger-display.c @@ -488,7 +488,7 @@ gnc_ledger_display_template_gl (char *id) } ld = gnc_ledger_display_internal (NULL, q, LD_GL, - GENERAL_LEDGER, + SEARCH_LEDGER, REG_STYLE_JOURNAL, FALSE, TRUE); /* TRUE : template mode */