This commit changes the GNCAccountSel widget to use a common account

list store based on the account-quickfill. Only the store is used here
with a filter model on top which is used by the combo.

When the first GAS is created, an account-quickfill list store is
created, kept up to date with account change events all subsequent uses
of GAS widget use this list store. With the use of a filter model the
GAS can tailored for use.
This commit is contained in:
Robert Fewell 2022-09-20 15:16:39 +01:00
parent e211626638
commit 8aa035144b
3 changed files with 305 additions and 266 deletions

View File

@ -28,6 +28,7 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include "account-quickfill.h"
#include "dialog-account.h" #include "dialog-account.h"
#include "gnc-account-sel.h" #include "gnc-account-sel.h"
#include "gnc-commodity.h" #include "gnc-commodity.h"
@ -37,7 +38,7 @@
#include "gnc-session.h" #include "gnc-session.h"
#include "dialog-utils.h" #include "dialog-utils.h"
#define ACCT_DATA_TAG "gnc-account-sel_acct" #define QKEY "gas_shared_quickfill"
/* Signal codes */ /* Signal codes */
enum enum
@ -58,17 +59,20 @@ enum account_cols
struct _GNCAccountSel struct _GNCAccountSel
{ {
GtkBox hbox; GtkBox hbox;
gboolean initDone;
gboolean isModal; gboolean isModal;
GtkListStore *store; GtkListStore *store;
GtkComboBox *combo; GtkComboBox *combo;
GList *acctTypeFilters; GList *acctTypeFilters;
GList *acctCommodityFilters; GList *acctCommodityFilters;
gint eventHandlerId; GList *acctExcludeList;
/* The state of this pointer also serves as a flag about what state /* The state of this pointer also serves as a flag about what state
* the widget is in WRT the new-account-button ability. */ * the widget is in WRT the new-account-button ability. */
GtkWidget *newAccountButton; GtkWidget *newAccountButton;
gint currentSelection; GtkTreeRowReference *saved_account_ref;
gulong row_changed_id;
gulong row_deleted_id;
char sep_key_prefix[BUFLEN]; char sep_key_prefix[BUFLEN];
gboolean hide_placeholder; gboolean hide_placeholder;
gboolean hide_hidden; gboolean hide_hidden;
@ -100,56 +104,13 @@ static void gas_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static void gas_filter_accounts (gpointer data, gpointer user_data);
static void gas_populate_list (GNCAccountSel *gas);
static void gas_new_account_click (GtkButton *b, gpointer ud); static void gas_new_account_click (GtkButton *b, gpointer ud);
static GtkBox *parent_class; static GtkBox *parent_class;
GType #define GNC_ACCOUNT_SEL_PATH "gnc-account-sel-path"
gnc_account_sel_get_type (void)
{
static GType account_sel_type = 0;
if (account_sel_type == 0) G_DEFINE_TYPE (GNCAccountSel, gnc_account_sel, GTK_TYPE_BOX)
{
GTypeInfo account_sel_info =
{
sizeof (GNCAccountSelClass),
NULL,
NULL,
(GClassInitFunc) gnc_account_sel_class_init,
NULL,
NULL,
sizeof (GNCAccountSel),
0,
(GInstanceInitFunc) gnc_account_sel_init
};
account_sel_type = g_type_register_static (GTK_TYPE_BOX,
"GNCAccountSel",
&account_sel_info, 0);
}
return account_sel_type;
}
static void
gnc_account_sel_event_cb (QofInstance *entity,
QofEventId event_type,
gpointer user_data,
gpointer event_data)
{
if (!(event_type == QOF_EVENT_CREATE
|| event_type == QOF_EVENT_MODIFY
|| event_type == QOF_EVENT_DESTROY)
|| !GNC_IS_ACCOUNT(entity))
{
return;
}
gas_populate_list ((GNCAccountSel*)user_data);
}
static void static void
gas_set_property (GObject *object, guint param_id, gas_set_property (GObject *object, guint param_id,
@ -269,7 +230,7 @@ gnc_account_sel_class_init (GNCAccountSelClass *klass)
"Should GAS take all horizontal space", TRUE, "Should GAS take all horizontal space", TRUE,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
g_object_class_install_property( g_object_class_install_property (
object_class, PROP_COMBO_ENTRY_WIDTH, object_class, PROP_COMBO_ENTRY_WIDTH,
g_param_spec_int("entry-width", "Number of Charactors", g_param_spec_int("entry-width", "Number of Charactors",
"Set the width of the combo entry", "Set the width of the combo entry",
@ -290,12 +251,39 @@ gnc_account_sel_class_init (GNCAccountSelClass *klass)
static void static void
combo_changed_cb (GNCAccountSel *gas, gpointer combo) combo_changed_cb (GNCAccountSel *gas, gpointer combo)
{ {
gint selected = gtk_combo_box_get_active (GTK_COMBO_BOX(combo)); GtkTreeModel *fmodel;
if (selected == gas->currentSelection) GtkTreeIter fiter;
GtkTreeIter iter;
GtkTreePath *path = NULL;
GtkTreePath *saved_account_path = NULL;
gboolean emit_signal = TRUE;
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(gas->combo), &fiter))
return; return;
gas->currentSelection = selected; fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
g_signal_emit_by_name (gas, "account_sel_changed"); gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(fmodel),
&iter, &fiter);
path = gtk_tree_model_get_path (GTK_TREE_MODEL(gas->store), &iter);
if (gas->saved_account_ref)
{
saved_account_path = gtk_tree_row_reference_get_path (gas->saved_account_ref);
gtk_tree_row_reference_free (gas->saved_account_ref);
}
gas->saved_account_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL(gas->store), path);
if (saved_account_path)
{
if (gtk_tree_path_compare (path, saved_account_path) == 0)
emit_signal = FALSE;
}
gtk_tree_path_free (saved_account_path);
gtk_tree_path_free (path);
if (emit_signal)
g_signal_emit_by_name (gas, "account_sel_changed");
} }
static char* static char*
@ -317,21 +305,21 @@ completion_function (GtkEntryCompletion *completion, const char *key,
GtkTreeIter *iter, gpointer user_data) GtkTreeIter *iter, gpointer user_data)
{ {
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data); GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
GtkTreeModel *fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
gchar *full_name = NULL; gchar *full_name = NULL;
gboolean ret = FALSE; gboolean ret = FALSE;
gtk_tree_model_get (GTK_TREE_MODEL(gas->store), iter, gtk_tree_model_get (fmodel, iter, ACCT_COL_NAME, &full_name, -1);
ACCT_COL_NAME, &full_name, -1);
if (full_name && *full_name) if (full_name && *full_name)
{ {
gchar *fold_full_name = normalize_and_fold (full_name); gchar *full_name_folded = normalize_and_fold (full_name);
// key is normalised and casefolded // key is normalised and casefolded
if (g_strrstr (fold_full_name, key) != NULL) if (g_strrstr (full_name_folded, key) != NULL)
ret = TRUE; ret = TRUE;
g_free (fold_full_name); g_free (full_name_folded);
} }
g_free (full_name); g_free (full_name);
return ret; return ret;
@ -495,16 +483,17 @@ entry_insert_text_cb (GtkEntry *entry, const gchar *text, gint length,
} }
static void static void
update_entry_and_list (GNCAccountSel *gas) update_entry_and_refilter (GNCAccountSel *gas)
{ {
GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo))); GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
GtkTreeModel *fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
g_signal_handlers_block_by_func (gas->combo, combo_changed_cb , gas); gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
gtk_entry_set_text (entry, ""); if (gas->saved_account_ref)
g_signal_handlers_unblock_by_func (gas->combo, combo_changed_cb , gas); gtk_tree_row_reference_free (gas->saved_account_ref);
gas->saved_account_ref = NULL;
// refresh the account list gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1);
gas_populate_list (gas); gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER(fmodel));
} }
static void static void
@ -512,7 +501,7 @@ toggle_placeholder_cb (GtkWidget *widget, gpointer user_data)
{ {
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data); GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
gas->hide_placeholder = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget)); gas->hide_placeholder = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget));
update_entry_and_list (gas); update_entry_and_refilter (gas);
} }
static void static void
@ -520,7 +509,7 @@ toggle_hidden_cb (GtkWidget *widget, gpointer user_data)
{ {
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data); GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
gas->hide_hidden = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget)); gas->hide_hidden = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget));
update_entry_and_list (gas); update_entry_and_refilter (gas);
} }
static void static void
@ -551,16 +540,23 @@ icon_release_cb (GtkEntry *entry, GtkEntryIconPosition icon_pos,
gtk_menu_popup_at_pointer (GTK_MENU(menu), (GdkEvent *)event); gtk_menu_popup_at_pointer (GTK_MENU(menu), (GdkEvent *)event);
} }
/* An account is included if gas->acctTypeFilters or gas->acctCommodityFilters is populated /* An account is included if gas->acctTypeFilters or gas->acctCommodityFilters
* and the account is in the list (both lists if both are populated). * is populated and the account is in the list (both lists if both are populated)
* and not in gas->acctExcludeList
* *
* If neither is populated then all accounts are included. * If no list is populated then all accounts are included.
*/ */
static gboolean static gboolean
account_is_included (GNCAccountSel *gas, Account *acc) account_is_included (GNCAccountSel *gas, Account *acc)
{ {
gboolean included = TRUE; gboolean included = TRUE;
if (gas->acctExcludeList)
{
if (g_list_find (gas->acctExcludeList, acc) != NULL)
included = FALSE;
}
/* Filter as we've been configured to do. */ /* Filter as we've been configured to do. */
if (gas->acctTypeFilters) if (gas->acctTypeFilters)
{ {
@ -586,33 +582,134 @@ account_is_included (GNCAccountSel *gas, Account *acc)
return included; return included;
} }
static gboolean
account_is_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
Account *acc;
gboolean visible = TRUE;
gtk_tree_model_get (GTK_TREE_MODEL(gas->store), iter, ACCT_COL_PTR, &acc, -1);
if (acc)
{
visible = account_is_included (gas, acc);
if (gas->hide_placeholder && xaccAccountGetPlaceholder (acc))
visible = FALSE;
if (gas->hide_placeholder && xaccAccountIsHidden (acc))
visible = FALSE;
}
return visible;
}
static void
row_has_been_deleted_in_store_cb (GtkTreeModel *model, GtkTreePath *path, gpointer user_data)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
GtkTreePath *saved_account_path;
if (!gas->saved_account_ref)
return;
saved_account_path = gtk_tree_row_reference_get_path (gas->saved_account_ref);
if (saved_account_path == NULL) // path is already invalid after row delete
{
GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
g_signal_handlers_block_by_func (gas->combo, combo_changed_cb , gas);
gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1);
gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
gtk_tree_row_reference_free (gas->saved_account_ref);
gas->saved_account_ref = NULL;
g_signal_emit_by_name (gas, "account_sel_changed");
g_signal_handlers_unblock_by_func (gas->combo, combo_changed_cb , gas);
}
gtk_tree_path_free (saved_account_path);
}
static void
row_has_been_changed_in_store_cb (GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer user_data)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
GtkTreePath *saved_account_path;
if (!gas->saved_account_ref)
return;
saved_account_path = gtk_tree_row_reference_get_path (gas->saved_account_ref);
if (gtk_tree_path_compare (path, saved_account_path) == 0)
{
GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
gchar *account_full_name = NULL;
gint position = 0;
g_signal_handlers_block_by_func (gas->combo, combo_changed_cb , gas);
gtk_tree_model_get (model, iter, ACCT_COL_NAME, &account_full_name, -1);
gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
gtk_editable_insert_text (GTK_EDITABLE(entry), account_full_name, -1, &position);
gtk_editable_set_position (GTK_EDITABLE(entry), -1);
g_free (account_full_name);
g_signal_handlers_unblock_by_func (gas->combo, combo_changed_cb , gas);
// see if account visibility has changed
if (!account_is_visible_func (model, iter, gas))
update_entry_and_refilter (gas);
}
gtk_tree_path_free (saved_account_path);
}
static void static void
gnc_account_sel_init (GNCAccountSel *gas) gnc_account_sel_init (GNCAccountSel *gas)
{ {
GtkWidget *widget; GtkWidget *widget;
GtkWidget *entry; GtkWidget *entry;
GtkEntryCompletion *completion; GtkEntryCompletion *completion;
Account *root = gnc_get_current_root_account ();
GtkTreeModel *filter_model;
gtk_orientable_set_orientation (GTK_ORIENTABLE(gas), GTK_ORIENTATION_HORIZONTAL); gtk_orientable_set_orientation (GTK_ORIENTABLE(gas), GTK_ORIENTATION_HORIZONTAL);
gas->initDone = FALSE; gas->acctTypeFilters = NULL;
gas->acctTypeFilters = FALSE; gas->acctCommodityFilters = NULL;
gas->acctExcludeList = NULL;
gas->newAccountButton = NULL; gas->newAccountButton = NULL;
gas->currentSelection = -1;
gas->hide_placeholder = TRUE; gas->hide_placeholder = TRUE;
gas->hide_hidden = TRUE; gas->hide_hidden = TRUE;
gas->saved_account_ref = NULL;
gas->row_changed_id = 0;
gas->row_deleted_id = 0;
g_object_set (gas, "spacing", 2, (gchar*)NULL); g_object_set (gas, "spacing", 2, (gchar*)NULL);
// Set the name for this widget so it can be easily manipulated with css // Set the name for this widget so it can be easily manipulated with css
gtk_widget_set_name (GTK_WIDGET(gas), "gnc-id-account-select"); gtk_widget_set_name (GTK_WIDGET(gas), "gnc-id-account-select");
gas->store = gtk_list_store_new (NUM_ACCT_COLS, G_TYPE_STRING, G_TYPE_POINTER); // We are just using the quickfill list store which will be the same for all
widget = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL(gas->store)); gas->store = gnc_get_shared_account_name_list_store (root, QKEY, NULL, NULL);
// set sort order
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(gas->store),
ACCT_COL_NAME, GTK_SORT_ASCENDING);
// the filter will be unique for each GAS.
filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL(gas->store), NULL);
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER(filter_model),
account_is_visible_func, gas, NULL);
widget = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL(filter_model));
g_object_unref (G_OBJECT(filter_model));
gas->combo = GTK_COMBO_BOX(widget); gas->combo = GTK_COMBO_BOX(widget);
gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX(widget), ACCT_COL_NAME); gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX(widget), ACCT_COL_NAME);
g_signal_connect_swapped (gas->combo, "changed",
G_CALLBACK(combo_changed_cb), gas);
gtk_container_add (GTK_CONTAINER(gas), widget); gtk_container_add (GTK_CONTAINER(gas), widget);
// set the default horizontal expansion to TRUE // set the default horizontal expansion to TRUE
@ -636,105 +733,18 @@ gnc_account_sel_init (GNCAccountSel *gas)
(GtkEntryCompletionMatchFunc)completion_function, (GtkEntryCompletionMatchFunc)completion_function,
gas, NULL); gas, NULL);
/* Get the accounts, place into combo list */ // Set default entry to none and blank entry
gas_populate_list (gas); gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1);
gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
// set sort order gas->row_deleted_id = g_signal_connect (G_OBJECT(gas->store), "row-deleted",
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(gas->store), G_CALLBACK(row_has_been_deleted_in_store_cb), gas);
ACCT_COL_NAME, GTK_SORT_ASCENDING);
gas->eventHandlerId = gas->row_changed_id = g_signal_connect (G_OBJECT(gas->store), "row-changed",
qof_event_register_handler (gnc_account_sel_event_cb, gas); G_CALLBACK(row_has_been_changed_in_store_cb), gas);
gas->initDone = TRUE; g_signal_connect_swapped (gas->combo, "changed",
} G_CALLBACK(combo_changed_cb), gas);
typedef struct
{
GNCAccountSel *gas;
GList *outList;
} account_filter_data;
static void
gas_populate_list (GNCAccountSel *gas)
{
account_filter_data atnd;
Account *root;
Account *acc;
GtkTreeIter iter;
GtkEntry *entry;
gint i, active = -1;
GList *accts, *ptr;
const gchar *currentSel;
entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
currentSel = gtk_entry_get_text (entry);
g_signal_handlers_block_by_func (gas->combo, combo_changed_cb , gas);
root = gnc_book_get_root_account (gnc_get_current_book ());
accts = gnc_account_get_descendants_sorted (root);
atnd.gas = gas;
atnd.outList = NULL;
g_list_foreach (accts, gas_filter_accounts, (gpointer)&atnd);
g_list_free (accts);
atnd.outList = g_list_reverse (atnd.outList);
gtk_list_store_clear (gas->store);
for (ptr = atnd.outList, i = 0; ptr; ptr = g_list_next(ptr), i++)
{
acc = ptr->data;
if (acc)
{
gchar *name = gnc_account_get_full_name (acc);
if (!(name && *name))
return;
gtk_list_store_append (gas->store, &iter);
gtk_list_store_set (gas->store, &iter,
ACCT_COL_NAME, name,
ACCT_COL_PTR, acc,
-1);
if (g_utf8_collate (name, currentSel) == 0)
active = i;
g_free (name);
}
}
/* If the account which was in the text box before still exists, then
* reset to it. */
if (active != -1)
gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), active);
g_signal_handlers_unblock_by_func (gas->combo, combo_changed_cb , gas);
g_list_free (atnd.outList);
}
static void
gas_filter_accounts (gpointer data, gpointer user_data)
{
account_filter_data *atnd;
Account *a;
atnd = (account_filter_data*)user_data;
a = (Account*)data;
if (atnd->gas->hide_placeholder && xaccAccountGetPlaceholder (a))
return;
if (atnd->gas->hide_placeholder && xaccAccountIsHidden (a))
return;
if (!account_is_included (atnd->gas, a))
return;
atnd->outList = g_list_prepend (atnd->outList, a);
} }
GtkWidget * GtkWidget *
@ -752,14 +762,14 @@ typedef struct
} gas_find_data; } gas_find_data;
static gboolean static gboolean
gnc_account_sel_find_account (GtkTreeModel *model, gnc_account_sel_find_account (GtkTreeModel *fmodel,
GtkTreePath *path, GtkTreePath *path,
GtkTreeIter *iter, GtkTreeIter *iter,
gas_find_data *data) gas_find_data *data)
{ {
Account *model_acc; Account *model_acc;
gtk_tree_model_get (model, iter, ACCT_COL_PTR, &model_acc, -1); gtk_tree_model_get (fmodel, iter, ACCT_COL_PTR, &model_acc, -1);
if (data->acct != model_acc) if (data->acct != model_acc)
return FALSE; return FALSE;
@ -771,7 +781,7 @@ gnc_account_sel_find_account (GtkTreeModel *model,
* and hide_hidden accordingly to show it. * and hide_hidden accordingly to show it.
*/ */
static void static void
check_account_can_be_seen (GNCAccountSel *gas, Account *acct) check_account_can_be_seen (GNCAccountSel *gas, GtkTreeModel *fmodel, Account *acct)
{ {
gboolean changed = FALSE; gboolean changed = FALSE;
gboolean included = account_is_included (gas, acct); gboolean included = account_is_included (gas, acct);
@ -793,7 +803,7 @@ check_account_can_be_seen (GNCAccountSel *gas, Account *acct)
changed = TRUE; changed = TRUE;
} }
if (changed) if (changed)
gas_populate_list (gas); gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER(fmodel));
} }
} }
@ -801,10 +811,16 @@ void
gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct, gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
gboolean set_default_acct) gboolean set_default_acct)
{ {
GtkTreeModel *fmodel;
gas_find_data data; gas_find_data data;
g_return_if_fail (gas != NULL);
g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
if (acct) if (acct)
check_account_can_be_seen (gas, acct); check_account_can_be_seen (gas, fmodel, acct);
if (set_default_acct) if (set_default_acct)
{ {
@ -824,7 +840,7 @@ gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
} }
data.gas = gas; data.gas = gas;
data.acct = acct; data.acct = acct;
gtk_tree_model_foreach (GTK_TREE_MODEL(gas->store), gtk_tree_model_foreach (GTK_TREE_MODEL(fmodel),
(GtkTreeModelForeachFunc)gnc_account_sel_find_account, (GtkTreeModelForeachFunc)gnc_account_sel_find_account,
&data); &data);
} }
@ -832,15 +848,24 @@ gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
Account* Account*
gnc_account_sel_get_account (GNCAccountSel *gas) gnc_account_sel_get_account (GNCAccountSel *gas)
{ {
GtkTreeModel *fmodel;
GtkTreeIter fiter;
GtkTreeIter iter; GtkTreeIter iter;
Account *acc; Account *acc;
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(gas->combo), &iter)) g_return_val_if_fail (gas != NULL, NULL);
g_return_val_if_fail (GNC_IS_ACCOUNT_SEL(gas), NULL);
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(gas->combo), &fiter))
return NULL; return NULL;
fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(fmodel),
&iter, &fiter);
gtk_tree_model_get (GTK_TREE_MODEL(gas->store), &iter, gtk_tree_model_get (GTK_TREE_MODEL(gas->store), &iter,
ACCT_COL_PTR, &acc, ACCT_COL_PTR, &acc, -1);
-1);
return acc; return acc;
} }
@ -848,6 +873,8 @@ void
gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters, gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters,
GList *commodityFilters) GList *commodityFilters)
{ {
g_return_if_fail (gas != NULL);
g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
if (gas->acctTypeFilters != NULL) if (gas->acctTypeFilters != NULL)
{ {
@ -861,10 +888,6 @@ gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters,
gas->acctCommodityFilters = NULL; gas->acctCommodityFilters = NULL;
} }
/* If both filters are null, then no filters exist. */
if ((!typeFilters) && (!commodityFilters))
return;
/* This works because the GNCAccountTypes in the list are /* This works because the GNCAccountTypes in the list are
* ints-casted-as-pointers. */ * ints-casted-as-pointers. */
if (typeFilters) if (typeFilters)
@ -874,7 +897,27 @@ gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters,
if (commodityFilters) if (commodityFilters)
gas->acctCommodityFilters = g_list_copy (commodityFilters); gas->acctCommodityFilters = g_list_copy (commodityFilters);
gas_populate_list (gas); update_entry_and_refilter (gas);
}
void
gnc_account_sel_set_acct_exclude_filter (GNCAccountSel *gas,
GList *excludeFilter)
{
g_return_if_fail (gas != NULL);
g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
if (gas->acctExcludeList != NULL)
{
g_list_free (gas->acctExcludeList);
gas->acctExcludeList = NULL;
}
if (excludeFilter)
gas->acctExcludeList = g_list_copy (excludeFilter);
update_entry_and_refilter (gas);
} }
static void static void
@ -893,6 +936,9 @@ gnc_account_sel_finalize (GObject *object)
if (gas->acctCommodityFilters) if (gas->acctCommodityFilters)
g_list_free (gas->acctCommodityFilters); g_list_free (gas->acctCommodityFilters);
if (gas->acctExcludeList)
g_list_free (gas->acctExcludeList);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -906,17 +952,17 @@ gnc_account_sel_dispose (GObject *object)
gas = GNC_ACCOUNT_SEL(object); gas = GNC_ACCOUNT_SEL(object);
if (gas->store) if (gas->row_changed_id > 0)
{ g_signal_handler_disconnect (G_OBJECT(gas->store), gas->row_changed_id);
g_object_unref (gas->store); gas->row_changed_id = 0;
gas->store = NULL;
}
if (gas->eventHandlerId) if (gas->row_deleted_id > 0)
{ g_signal_handler_disconnect (G_OBJECT(gas->store), gas->row_deleted_id);
qof_event_unregister_handler (gas->eventHandlerId); gas->row_deleted_id = 0;
gas->eventHandlerId = 0;
} if (gas->saved_account_ref)
gtk_tree_row_reference_free (gas->saved_account_ref);
gas->saved_account_ref = NULL;
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }
@ -926,6 +972,7 @@ gnc_account_sel_set_new_account_ability (GNCAccountSel *gas,
gboolean state) gboolean state)
{ {
g_return_if_fail (gas != NULL); g_return_if_fail (gas != NULL);
g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
if (state == (gas->newAccountButton != NULL)) if (state == (gas->newAccountButton != NULL))
{ {
@ -959,19 +1006,21 @@ gnc_account_sel_set_new_account_modal (GNCAccountSel *gas,
gboolean state) gboolean state)
{ {
g_return_if_fail (gas != NULL); g_return_if_fail (gas != NULL);
g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
gas->isModal = state; gas->isModal = state;
} }
static void static void
gas_new_account_click (GtkButton *b, gpointer ud) gas_new_account_click (GtkButton *b, gpointer user_data)
{ {
GNCAccountSel *gas = (GNCAccountSel*)ud; GNCAccountSel *gas = (GNCAccountSel*)user_data;
Account *account = NULL;
GtkWindow *parent = GTK_WINDOW(gtk_widget_get_toplevel (GTK_WIDGET(gas))); GtkWindow *parent = GTK_WINDOW(gtk_widget_get_toplevel (GTK_WIDGET(gas)));
if (gas->isModal) if (gas->isModal)
{ {
account = gnc_ui_new_accounts_from_name_window_with_types (parent, NULL, Account *account = gnc_ui_new_accounts_from_name_window_with_types (parent, NULL,
gas->acctTypeFilters); gas->acctTypeFilters);
if (account) if (account)
gnc_account_sel_set_account (gas, account, FALSE); gnc_account_sel_set_account (gas, account, FALSE);
} }
@ -981,58 +1030,14 @@ gas_new_account_click (GtkButton *b, gpointer ud)
} }
gint gint
gnc_account_sel_get_num_account (GNCAccountSel *gas) gnc_account_sel_get_visible_account_num (GNCAccountSel *gas)
{ {
if (NULL == gas) GtkTreeModel *fmodel;
return 0;
return gtk_tree_model_iter_n_children (GTK_TREE_MODEL(gas->store), NULL); g_return_val_if_fail (gas != NULL, 0);
} g_return_val_if_fail (GNC_IS_ACCOUNT_SEL(gas), 0);
void fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
gnc_account_sel_purge_account (GNCAccountSel *gas,
Account *target, return gtk_tree_model_iter_n_children (fmodel, NULL);
gboolean recursive)
{
GtkTreeModel *model = GTK_TREE_MODEL(gas->store);
GtkTreeIter iter;
Account *acc;
gboolean more;
if (!gtk_tree_model_get_iter_first (model, &iter))
return;
if (!recursive)
{
do
{
gtk_tree_model_get (model, &iter, ACCT_COL_PTR, &acc, -1);
if (acc == target)
{
gtk_list_store_remove (gas->store, &iter);
break;
}
}
while (gtk_tree_model_iter_next (model, &iter));
}
else
{
do
{
gtk_tree_model_get (model, &iter, ACCT_COL_PTR, &acc, -1);
while (acc)
{
if (acc == target)
break;
acc = gnc_account_get_parent (acc);
}
if (acc == target)
more = gtk_list_store_remove (gas->store, &iter);
else
more = gtk_tree_model_iter_next (model, &iter);
}
while (more);
}
gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), 0);
} }

View File

@ -48,7 +48,7 @@ typedef struct
void (*account_sel_changed) (GNCAccountSel *gas); void (*account_sel_changed) (GNCAccountSel *gas);
} GNCAccountSelClass; } GNCAccountSelClass;
GType gnc_account_sel_get_type (void); GType gnc_account_sel_get_type (void) G_GNUC_CONST;
GtkWidget* gnc_account_sel_new (void); GtkWidget* gnc_account_sel_new (void);
/** /**
@ -56,13 +56,14 @@ GtkWidget* gnc_account_sel_new (void);
* list, then it doesn't change the state of the GAS. If the account is * list, then it doesn't change the state of the GAS. If the account is
* NULL, then the first list selection is made if set_default_acct is TRUE. * NULL, then the first list selection is made if set_default_acct is TRUE.
**/ **/
void gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct, void gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
gboolean set_default_acct); gboolean set_default_acct);
/** /**
* Returns the currently-selected Account. If, for some reason the selection * Returns the currently-selected Account. If, for some reason the selection
* is in a bad state, NULL will be returned. * is in a bad state, NULL will be returned.
**/ **/
Account* gnc_account_sel_get_account (GNCAccountSel *gas); Account* gnc_account_sel_get_account (GNCAccountSel *gas);
/** /**
* The GNCAccountSel can be setup to filter the accounts displayed. * The GNCAccountSel can be setup to filter the accounts displayed.
@ -70,9 +71,19 @@ Account* gnc_account_sel_get_account (GNCAccountSel *gas);
* @param commodityFilters A GList of gnc_commodity types which are allowed. * @param commodityFilters A GList of gnc_commodity types which are allowed.
* The list is copied, of course. * The list is copied, of course.
**/ **/
void gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters, void gnc_account_sel_set_acct_filters (GNCAccountSel *gas,
GList *typeFilters,
GList *commodityFilters); GList *commodityFilters);
/**
* The GNCAccountSel can be setup to filter the accounts displayed.
* @param gas The GNCAccountSel widget.
* @param excludeFilter A GList of accounts to be excluded.
* The list is copied, of course.
**/
void gnc_account_sel_set_acct_exclude_filter (GNCAccountSel *gas,
GList *excludeFilter);
/** /**
* Conditional inclusion of a new-account button to the right of the * Conditional inclusion of a new-account button to the right of the
* combobox. * combobox.
@ -86,7 +97,12 @@ void gnc_account_sel_set_new_account_ability (GNCAccountSel *gas, gboolean state
**/ **/
void gnc_account_sel_set_new_account_modal (GNCAccountSel *gas, gboolean state); void gnc_account_sel_set_new_account_modal (GNCAccountSel *gas, gboolean state);
gint gnc_account_sel_get_num_account (GNCAccountSel *gas); /**
void gnc_account_sel_purge_account (GNCAccountSel *gas, Account *acc, gboolean recursive); * Get the number of accounts visible.
*
* @param gas The GNCAccountSel widget.
* @return The number of visible accounts from the filter model.
**/
gint gnc_account_sel_get_visible_account_num (GNCAccountSel *gas);
#endif /* GNC_ACCOUNT_SEL_H */ #endif /* GNC_ACCOUNT_SEL_H */

View File

@ -1316,8 +1316,8 @@ set_ok_sensitivity(GtkWidget *dialog)
sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS); sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS);
trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS); trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
sa_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(sa_mas)); sa_mas_cnt = gnc_account_sel_get_visible_account_num(GNC_ACCOUNT_SEL(sa_mas));
trans_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(trans_mas)); trans_mas_cnt = gnc_account_sel_get_visible_account_num(GNC_ACCOUNT_SEL(trans_mas));
sensitive = (((NULL == sa_mas) || sensitive = (((NULL == sa_mas) ||
(!gtk_widget_is_sensitive(sa_mas) || sa_mas_cnt)) && (!gtk_widget_is_sensitive(sa_mas) || sa_mas_cnt)) &&
@ -1328,6 +1328,19 @@ set_ok_sensitivity(GtkWidget *dialog)
gtk_widget_set_sensitive(button, sensitive); gtk_widget_set_sensitive(button, sensitive);
} }
static GList *
gppat_get_exclude_list (Account *acc, gboolean exclude_subaccounts)
{
GList *acct_list = NULL;
if (exclude_subaccounts)
acct_list = gnc_account_get_descendants (acc);
acct_list = g_list_prepend (acct_list, acc);
return acct_list;
}
static void static void
gppat_populate_gas_list(GtkWidget *dialog, gppat_populate_gas_list(GtkWidget *dialog,
GNCAccountSel *gas, GNCAccountSel *gas,
@ -1335,6 +1348,7 @@ gppat_populate_gas_list(GtkWidget *dialog,
{ {
Account *account; Account *account;
GList *filter; GList *filter;
GList *exclude;
g_return_if_fail(GTK_IS_DIALOG(dialog)); g_return_if_fail(GTK_IS_DIALOG(dialog));
if (gas == NULL) if (gas == NULL)
@ -1345,8 +1359,12 @@ gppat_populate_gas_list(GtkWidget *dialog,
/* Setting the account type filter triggers GNCAccountSel population. */ /* Setting the account type filter triggers GNCAccountSel population. */
gnc_account_sel_set_acct_filters (gas, filter, NULL); gnc_account_sel_set_acct_filters (gas, filter, NULL);
/* Accounts to be deleted must be removed. */ /* Accounts to be deleted must be excluded from GAS. */
gnc_account_sel_purge_account( gas, account, exclude_subaccounts); exclude = gppat_get_exclude_list (account, exclude_subaccounts);
gnc_account_sel_set_acct_exclude_filter (gas, exclude);
g_list_free (exclude);
gnc_account_sel_set_account (gas, NULL, TRUE);
/* The sensitivity of the OK button needs to be reevaluated. */ /* The sensitivity of the OK button needs to be reevaluated. */
set_ok_sensitivity(dialog); set_ok_sensitivity(dialog);