diff --git a/ChangeLog b/ChangeLog index 93e139748d..df0dbf08ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2006-03-12 David Hampton + + * src/register/register-gnome/gnucash-sheet.[ch]: + * src/register/ledger-core/split-register.[ch]: + * src/register/ledger-core/split-register-control.c: + * src/gnome/gnc-split-reg.[ch]: + * src/gnome/gnc-plugin-page-register.c: + * src/engine/Transaction.h: Replace the changes in r13361 with a + better method for determining when a change in the register needs + to be reflected in the available user actions. Now updates the + Void and Unvoid actions which implements the enhancement request + in 330763. + 2006-03-11 David Hampton * src/register/register-gnome/combocell-gnome.c: diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h index 07004ea520..1caf7b81de 100644 --- a/src/engine/Transaction.h +++ b/src/engine/Transaction.h @@ -92,6 +92,9 @@ Splits plus the value of all of its sub-Accounts. #include "gnc-engine.h" #include "Split.h" +#define GNC_IS_TRANS(obj) (QOF_CHECK_TYPE((obj), GNC_ID_TRANS)) +#define GNC_TRANS(obj) (QOF_CHECK_CAST((obj), GNC_ID_TRANS, Transaction)) + /** @name Transaction Type field values @{ */ diff --git a/src/gnome/gnc-plugin-page-register.c b/src/gnome/gnc-plugin-page-register.c index 166d33ffb6..7c15f3bee4 100644 --- a/src/gnome/gnc-plugin-page-register.c +++ b/src/gnome/gnc-plugin-page-register.c @@ -2,7 +2,7 @@ * gnc-plugin-page-register.c -- * * Copyright (C) 2003 Jan Arne Petersen - * Copyright (C) 2003,2005 David Hampton + * Copyright (C) 2003,2005,2006 David Hampton * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -57,6 +57,7 @@ #include "gnc-date.h" #include "gnc-date-edit.h" #include "gnc-engine.h" +#include "gnc-event.h" #include "gnc-gnome-utils.h" #include "gnc-gobject-utils.h" #include "gnc-gui-query.h" @@ -148,8 +149,12 @@ static void gnc_plugin_page_register_cmd_transaction_report (GtkAction *action, static void gnc_plugin_page_help_changed_cb( GNCSplitReg *gsr, GncPluginPageRegister *register_page ); static void gnc_plugin_page_register_refresh_cb (GHashTable *changes, gpointer user_data); -static void gnc_plugin_page_register_update_split_button (SplitRegister *reg, GncPluginPageRegister *page); +static void gnc_plugin_page_register_ui_update (gpointer various, GncPluginPageRegister *page); static void gppr_account_destroy_cb (Account *account); +static void gnc_plugin_page_register_event_handler (QofEntity *entity, + QofEventId event_type, + GncPluginPageRegister *page, + GncEventData *ed); /************************************************************/ /* Actions */ @@ -355,6 +360,7 @@ typedef struct GncPluginPageRegisterPrivate GtkWidget *widget; + gint event_handler_id; gint component_manager_id; GUID key; /* The guid of the Account we're watching */ @@ -456,8 +462,6 @@ gnc_plugin_page_register_new_common (GNCLedgerDisplay *ledger) // Do not free the list. It is owned by the query. reg = gnc_ledger_display_get_split_register(priv->ledger); - gnc_split_register_set_trans_collapsed_cb - (reg, (GFunc)gnc_plugin_page_register_update_split_button, register_page); priv->component_manager_id = 0; return plugin_page; @@ -600,38 +604,41 @@ gnc_plugin_page_register_get_account (GncPluginPageRegister *page) static void -gnc_plugin_page_register_update_split_button (SplitRegister *reg, GncPluginPageRegister *page) +gnc_plugin_page_register_ui_update (gpointer various, GncPluginPageRegister *page) { + GncPluginPageRegisterPrivate *priv; + SplitRegister *reg; GtkAction *action; - gboolean expanded; + gboolean expanded, voided; + Transaction *trans; + /* Set 'Split Transaction' */ + priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page); + reg = gnc_ledger_display_get_split_register(priv->ledger); expanded = gnc_split_register_current_trans_expanded(reg); action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SplitTransactionAction"); - + gtk_action_set_sensitive (action, reg->style == REG_STYLE_LEDGER); g_signal_handlers_block_by_func (action, gnc_plugin_page_register_cmd_expand_transaction, page); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION(action), expanded); g_signal_handlers_unblock_by_func (action, gnc_plugin_page_register_cmd_expand_transaction, page); -} -static void -gnc_plugin_page_register_update_toolbar (SplitRegister *reg, GncPluginPageRegister *page) -{ - GtkAction *action; + /* Set 'Void' and 'Unvoid' */ + trans = gnc_split_register_get_current_trans(reg); + voided = xaccTransHasSplitsInState(trans, VREC); + action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), + "VoidTransactionAction"); + gtk_action_set_sensitive (GTK_ACTION(action), !voided); action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), - "SplitTransactionAction"); - /* set sensitivity of split button */ - gtk_action_set_sensitive (action, reg->style == REG_STYLE_LEDGER); - - /* set activity of split button */ - gnc_plugin_page_register_update_split_button (reg, page); + "UnvoidTransactionAction"); + gtk_action_set_sensitive (GTK_ACTION(action), voided); } static void -gnc_plugin_page_register_update_menus (GncPluginPageRegister *page) +gnc_plugin_page_register_ui_initial_state (GncPluginPageRegister *page) { GncPluginPageRegisterPrivate *priv ; GtkActionGroup *action_group; @@ -726,8 +733,8 @@ gnc_plugin_page_register_create_widget (GncPluginPage *plugin_page) reg->use_double_line); gnc_ledger_display_refresh(priv->ledger); - gnc_plugin_page_register_update_menus (page); - gnc_plugin_page_register_update_toolbar (reg, page); + gnc_plugin_page_register_ui_initial_state (page); + gnc_plugin_page_register_ui_update (NULL, page); plugin_page->summarybar = gsr_create_summary_bar(priv->gsr); if (plugin_page->summarybar) { @@ -736,6 +743,8 @@ gnc_plugin_page_register_create_widget (GncPluginPage *plugin_page) FALSE, FALSE, 0); } + priv->event_handler_id = qof_event_register_handler + ((QofEventHandler)gnc_plugin_page_register_event_handler, page); priv->component_manager_id = gnc_register_gui_component(GNC_PLUGIN_PAGE_REGISTER_NAME, gnc_plugin_page_register_refresh_cb, @@ -748,6 +757,8 @@ gnc_plugin_page_register_create_widget (GncPluginPage *plugin_page) priv->component_manager_id, xaccAccountGetGUID(acct), QOF_EVENT_DESTROY | QOF_EVENT_MODIFY); + gnc_split_reg_set_moved_cb + (priv->gsr, (GFunc)gnc_plugin_page_register_ui_update, page); /* DRH - Probably lots of other stuff from regWindowLedger should end up here. */ LEAVE(" "); @@ -772,6 +783,11 @@ gnc_plugin_page_register_destroy_widget (GncPluginPage *plugin_page) priv->component_manager_id = 0; } + if (priv->event_handler_id) { + qof_event_unregister_handler(priv->event_handler_id); + priv->event_handler_id = 0; + } + if (priv->sd.dialog) { gtk_widget_destroy(priv->sd.dialog); memset(&priv->sd, 0, sizeof(priv->sd)); @@ -1895,10 +1911,8 @@ gnc_plugin_page_register_cmd_void_transaction (GtkAction *action, trans = gnc_split_register_get_current_trans(reg); if (trans == NULL) return; - if (xaccTransHasSplitsInState(trans, VREC)) { - gnc_error_dialog(NULL, _("This transaction has already been voided.")); + if (xaccTransHasSplitsInState(trans, VREC)) return; - } if (xaccTransHasReconciledSplits(trans) || xaccTransHasSplitsInState(trans, CREC)) { gnc_error_dialog(NULL, _("You cannot void a transaction with reconciled or cleared splits.")); return; @@ -1937,10 +1951,8 @@ gnc_plugin_page_register_cmd_unvoid_transaction (GtkAction *action, priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page); reg = gnc_ledger_display_get_split_register(priv->ledger); trans = gnc_split_register_get_current_trans(reg); - if (!xaccTransHasSplitsInState(trans, VREC)) { - gnc_error_dialog(NULL, _("This transaction is not voided.")); + if (!xaccTransHasSplitsInState(trans, VREC)) return; - } gnc_split_register_unvoid_current_trans(reg); LEAVE(" "); } @@ -2174,7 +2186,6 @@ gnc_plugin_page_register_cmd_style_changed (GtkAction *action, GncPluginPageRegister *plugin_page) { GncPluginPageRegisterPrivate *priv; - SplitRegister *reg; SplitRegisterStyle value; ENTER("(action %p, radio action %p, plugin_page %p)", @@ -2188,8 +2199,7 @@ gnc_plugin_page_register_cmd_style_changed (GtkAction *action, value = gtk_radio_action_get_current_value(current); gnc_split_reg_change_style(priv->gsr, value); - reg = gnc_ledger_display_get_split_register(priv->ledger); - gnc_plugin_page_register_update_toolbar (reg, plugin_page); + gnc_plugin_page_register_ui_update (NULL, plugin_page); LEAVE(" "); } @@ -2731,6 +2741,8 @@ gnc_plugin_page_register_refresh_cb (GHashTable *changes, gpointer user_data) gnucash_register_refresh_from_gconf(priv->gsr->reg); gtk_widget_queue_draw(priv->widget); } + + gnc_plugin_page_register_ui_update(NULL, page); } /** This function is called when an account has been edited and an @@ -2777,5 +2789,76 @@ gppr_account_destroy_cb (Account *account) } } +/** This function is the handler for all event messages from the + * engine. Its purpose is to update the account tree model any time + * an account is added to the engine or deleted from the engine. + * This change to the model is then propagated to any/all overlying + * filters and views. This function listens to the ADD, REMOVE, and + * DESTROY events. + * + * @internal + * + * @warning There is a "Catch 22" situation here. + * gtk_tree_model_row_deleted() can't be called until after the item + * has been deleted from the real model (which is the engine's + * account tree for us), but once the account has been deleted from + * the engine we have no way to determine the path to pass to + * row_deleted(). This is a PITA, but the only other choice is to + * have this model mirror the engine's accounts instead of + * referencing them directly. + * + * @param entity The guid of the affected item. + * + * @param type The type of the affected item. This function only + * cares about items of type "account". + * + * @param event type The type of the event. This function only cares + * about items of type ADD, REMOVE, MODIFY, and DESTROY. + * + * @param user_data A pointer to the account tree model. + */ +static void +gnc_plugin_page_register_event_handler (QofEntity *entity, + QofEventId event_type, + GncPluginPageRegister *page, + GncEventData *ed) +{ + Transaction *trans; + QofBook *book; + GncPluginPage *visible_page; + GtkWidget *window; + + g_return_if_fail(page); /* Required */ + if (!GNC_IS_TRANS(entity)) + return; + + ENTER("entity %p of type %d, page %p, event data %p", + entity, event_type, page, ed); + + if (!(event_type & (QOF_EVENT_MODIFY | QOF_EVENT_DESTROY))) { + LEAVE("not a modify"); + return; + } + trans = GNC_TRANS(entity); + book = qof_instance_get_book(QOF_INSTANCE(trans)); + if (!gnc_plugin_page_has_book(GNC_PLUGIN_PAGE(page), book)) { + + LEAVE("not in this book"); + return; + } + + window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page)); + visible_page = gnc_main_window_get_current_page(GNC_MAIN_WINDOW(window)); + if (GNC_PLUGIN_PAGE(page) != visible_page) { + LEAVE("page not visible"); + return; + } + + gnc_plugin_page_register_ui_update(NULL, page); + LEAVE(" "); + return; +} + + /** @} */ /** @} */ diff --git a/src/gnome/gnc-split-reg.c b/src/gnome/gnc-split-reg.c index 634c533b43..0c51b43f26 100644 --- a/src/gnome/gnc-split-reg.c +++ b/src/gnome/gnc-split-reg.c @@ -2021,3 +2021,9 @@ gnc_split_reg_get_read_only( GNCSplitReg *gsr ) g_assert( gsr ); return gsr->read_only; } + +void +gnc_split_reg_set_moved_cb( GNCSplitReg *gsr, GFunc cb, gpointer cb_data ) +{ + gnucash_register_set_moved_cb (gsr->reg, cb, cb_data); +} diff --git a/src/gnome/gnc-split-reg.h b/src/gnome/gnc-split-reg.h index 51bfef25b0..c4717e7d4e 100644 --- a/src/gnome/gnc-split-reg.h +++ b/src/gnome/gnc-split-reg.h @@ -238,4 +238,6 @@ void gsr_default_reinit_handler( GNCSplitReg *gsr, gpointer data ); void gsr_default_expand_handler( GNCSplitReg *gsr, gpointer data ); void gsr_default_schedule_handler( GNCSplitReg *gsr, gpointer data ); +void gnc_split_reg_set_moved_cb( GNCSplitReg *gsr, GFunc cb, gpointer cb_data ); + #endif /* GNC_SPLIT_REG_H */ diff --git a/src/register/ledger-core/split-register-control.c b/src/register/ledger-core/split-register-control.c index f66999ae46..5464285d35 100644 --- a/src/register/ledger-core/split-register-control.c +++ b/src/register/ledger-core/split-register-control.c @@ -423,7 +423,7 @@ gnc_split_register_move_cursor (VirtualLocation *p_new_virt_loc, reg->style == REG_STYLE_JOURNAL); } - gnc_split_register_collapse_current_trans(reg); + info->trans_expanded = FALSE; do_refresh = TRUE; } diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c index 7c19ef6ea8..c633acdd71 100644 --- a/src/register/ledger-core/split-register.c +++ b/src/register/ledger-core/split-register.c @@ -205,30 +205,6 @@ gnc_split_register_expand_current_trans (SplitRegister *reg, gboolean expand) reg->table->current_cursor_loc.vcell_loc); } -void -gnc_split_register_collapse_current_trans (SplitRegister *reg) -{ - SRInfo *info = gnc_split_register_get_info (reg); - - if (!reg) - return; - - info->trans_expanded = FALSE; - if (reg->expand_changed_cb) - (reg->expand_changed_cb)(reg, reg->expand_changed_cb_data); -} - -void -gnc_split_register_set_trans_collapsed_cb (SplitRegister *reg, GFunc cb, - gpointer cb_data) -{ - if (!reg) - return; - - reg->expand_changed_cb = cb; - reg->expand_changed_cb_data = cb_data; -} - gboolean gnc_split_register_current_trans_expanded (SplitRegister *reg) { @@ -536,7 +512,7 @@ gnc_split_register_duplicate_current (SplitRegister *reg) info->cursor_hint_trans_split = trans_split; info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS; - gnc_split_register_collapse_current_trans(reg); + info->trans_expanded = FALSE; } /* Refresh the GUI. */ @@ -923,7 +899,7 @@ gnc_split_register_delete_current_trans (SplitRegister *reg) return; } - gnc_split_register_collapse_current_trans(reg); + info->trans_expanded = FALSE; gnc_suspend_gui_refresh (); @@ -975,7 +951,7 @@ gnc_split_register_void_current_trans (SplitRegister *reg, const char *reason) if (xaccSplitGetReconcile (split) == VREC) return; - gnc_split_register_collapse_current_trans(reg); + info->trans_expanded = FALSE; gnc_suspend_gui_refresh (); @@ -1024,7 +1000,7 @@ gnc_split_register_unvoid_current_trans (SplitRegister *reg) if (xaccSplitGetReconcile (split) != VREC) return; - gnc_split_register_collapse_current_trans(reg); + info->trans_expanded = FALSE; gnc_suspend_gui_refresh (); diff --git a/src/register/ledger-core/split-register.h b/src/register/ledger-core/split-register.h index 16750e4b27..71628ecf56 100644 --- a/src/register/ledger-core/split-register.h +++ b/src/register/ledger-core/split-register.h @@ -240,9 +240,6 @@ struct split_register { Table * table; /**< The table itself that implements the underlying GUI. */ - GFunc expand_changed_cb; - gpointer expand_changed_cb_data; - SplitRegisterType type; SplitRegisterStyle style; @@ -416,11 +413,6 @@ void gnc_split_register_expand_current_trans (SplitRegister *reg, /** Mark the current transaction as collapsed, and do callbacks. */ void gnc_split_register_collapse_current_trans (SplitRegister *reg); -/** Register a callback function for when the register closes a - * transaction without the user explicitly asking for this to - * be changed. */ -void gnc_split_register_set_trans_collapsed_cb (SplitRegister *reg, GFunc cb, gpointer cb_data); - /** Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER. */ gboolean gnc_split_register_current_trans_expanded (SplitRegister *reg); diff --git a/src/register/register-gnome/gnucash-sheet.c b/src/register/register-gnome/gnucash-sheet.c index 54c204b01b..5ed704cd2f 100644 --- a/src/register/register-gnome/gnucash-sheet.c +++ b/src/register/register-gnome/gnucash-sheet.c @@ -309,6 +309,8 @@ gnucash_sheet_cursor_move (GnucashSheet *sheet, VirtualLocation virt_loc) /* Now turn on the editing controls. */ gnucash_sheet_activate_cursor_cell (sheet, changed_cells); + if (sheet->moved_cb) + (sheet->moved_cb)(sheet, sheet->moved_cb_data); return changed_cells; } @@ -2620,6 +2622,19 @@ gnucash_register_new (Table *table) } +void gnucash_register_set_moved_cb (GnucashRegister *reg, + GFunc cb, gpointer cb_data) +{ + GnucashSheet *sheet; + + if (!reg || !reg->sheet) + return; + sheet = GNUCASH_SHEET(reg->sheet); + sheet->moved_cb = cb; + sheet->moved_cb_data = cb_data; +} + + /* Local Variables: c-basic-offset: 8 diff --git a/src/register/register-gnome/gnucash-sheet.h b/src/register/register-gnome/gnucash-sheet.h index a2686d9a24..7a766ac62d 100644 --- a/src/register/register-gnome/gnucash-sheet.h +++ b/src/register/register-gnome/gnucash-sheet.h @@ -123,6 +123,9 @@ typedef struct guint changed_signal; GtkAdjustment *hadj, *vadj; + + GFunc moved_cb; + gpointer moved_cb_data; } GnucashSheet; @@ -149,10 +152,6 @@ GType gnucash_register_get_type (void); /* this already has scrollbars attached */ GtkWidget *gnucash_register_new (Table *table); -void gnucash_sheet_set_top_block (GnucashSheet *sheet, int new_top_block, - gint align); - - SheetBlock *gnucash_sheet_get_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc); @@ -214,6 +213,8 @@ void gnucash_register_cut_clipboard (GnucashRegister *reg); void gnucash_register_copy_clipboard (GnucashRegister *reg); void gnucash_register_paste_clipboard (GnucashRegister *reg); void gnucash_register_refresh_from_gconf (GnucashRegister *reg); +void gnucash_register_set_moved_cb (GnucashRegister *reg, + GFunc cb, gpointer cb_data); typedef struct {