gnucash master: Multiple changes pushed
John Ralls
jralls at code.gnucash.org
Tue Jan 24 17:07:40 EST 2023
Updated via https://github.com/Gnucash/gnucash/commit/4739e8ce (commit)
via https://github.com/Gnucash/gnucash/commit/8aa03514 (commit)
via https://github.com/Gnucash/gnucash/commit/e2116266 (commit)
via https://github.com/Gnucash/gnucash/commit/4d96c0d7 (commit)
via https://github.com/Gnucash/gnucash/commit/13bb321c (commit)
via https://github.com/Gnucash/gnucash/commit/1d163b7f (commit)
via https://github.com/Gnucash/gnucash/commit/3b3f574c (commit)
from https://github.com/Gnucash/gnucash/commit/f6919e60 (commit)
commit 4739e8ce04f6ae5f614aa8732f93cefbd316b1f9
Merge: f6919e60a 8aa035144
Author: John Ralls <jralls at ceridwen.us>
Date: Tue Jan 24 13:36:50 2023 -0800
Merge Bob Fewell's 'bug798475' into master.
diff --cc gnucash/gnome-utils/gnc-account-sel.h
index 297f58f6f,3820a8969..a71a077ea
--- a/gnucash/gnome-utils/gnc-account-sel.h
+++ b/gnucash/gnome-utils/gnc-account-sel.h
@@@ -108,12 -97,12 +101,16 @@@ void gnc_account_sel_set_new_account_ab
**/
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);
- void gnc_account_sel_set_hexpand (GNCAccountSel *gas, gboolean expand);
+ /**
+ * 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);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* GNC_ACCOUNT_SEL_H */
commit 8aa035144bc68dbfacd2252af7792baf6abe9a4c
Author: Robert Fewell <14uBobIT at gmail.com>
Date: Tue Sep 20 15:16:39 2022 +0100
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.
diff --git a/gnucash/gnome-utils/gnc-account-sel.c b/gnucash/gnome-utils/gnc-account-sel.c
index 950712d66..45a492605 100644
--- a/gnucash/gnome-utils/gnc-account-sel.c
+++ b/gnucash/gnome-utils/gnc-account-sel.c
@@ -28,6 +28,7 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include "account-quickfill.h"
#include "dialog-account.h"
#include "gnc-account-sel.h"
#include "gnc-commodity.h"
@@ -37,7 +38,7 @@
#include "gnc-session.h"
#include "dialog-utils.h"
-#define ACCT_DATA_TAG "gnc-account-sel_acct"
+#define QKEY "gas_shared_quickfill"
/* Signal codes */
enum
@@ -58,17 +59,20 @@ enum account_cols
struct _GNCAccountSel
{
GtkBox hbox;
- gboolean initDone;
gboolean isModal;
GtkListStore *store;
GtkComboBox *combo;
GList *acctTypeFilters;
GList *acctCommodityFilters;
- gint eventHandlerId;
+ GList *acctExcludeList;
+
/* 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;
- gint currentSelection;
+ GtkTreeRowReference *saved_account_ref;
+ gulong row_changed_id;
+ gulong row_deleted_id;
+
char sep_key_prefix[BUFLEN];
gboolean hide_placeholder;
gboolean hide_hidden;
@@ -100,56 +104,13 @@ static void gas_get_property (GObject *object,
GValue *value,
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 GtkBox *parent_class;
-GType
-gnc_account_sel_get_type (void)
-{
- static GType account_sel_type = 0;
+#define GNC_ACCOUNT_SEL_PATH "gnc-account-sel-path"
- if (account_sel_type == 0)
- {
- 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);
-}
+G_DEFINE_TYPE (GNCAccountSel, gnc_account_sel, GTK_TYPE_BOX)
static void
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,
G_PARAM_READWRITE));
- g_object_class_install_property(
+ g_object_class_install_property (
object_class, PROP_COMBO_ENTRY_WIDTH,
g_param_spec_int("entry-width", "Number of Charactors",
"Set the width of the combo entry",
@@ -290,12 +251,39 @@ gnc_account_sel_class_init (GNCAccountSelClass *klass)
static void
combo_changed_cb (GNCAccountSel *gas, gpointer combo)
{
- gint selected = gtk_combo_box_get_active (GTK_COMBO_BOX(combo));
- if (selected == gas->currentSelection)
+ GtkTreeModel *fmodel;
+ 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;
- gas->currentSelection = selected;
- g_signal_emit_by_name (gas, "account_sel_changed");
+ 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);
+
+ 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*
@@ -317,21 +305,21 @@ completion_function (GtkEntryCompletion *completion, const char *key,
GtkTreeIter *iter, gpointer 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;
gboolean ret = FALSE;
- gtk_tree_model_get (GTK_TREE_MODEL(gas->store), iter,
- ACCT_COL_NAME, &full_name, -1);
+ gtk_tree_model_get (fmodel, iter, ACCT_COL_NAME, &full_name, -1);
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
- if (g_strrstr (fold_full_name, key) != NULL)
+ if (g_strrstr (full_name_folded, key) != NULL)
ret = TRUE;
- g_free (fold_full_name);
+ g_free (full_name_folded);
}
g_free (full_name);
return ret;
@@ -495,16 +483,17 @@ entry_insert_text_cb (GtkEntry *entry, const gchar *text, gint length,
}
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)));
+ 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_entry_set_text (entry, "");
- g_signal_handlers_unblock_by_func (gas->combo, combo_changed_cb , gas);
-
- // refresh the account list
- gas_populate_list (gas);
+ gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
+ if (gas->saved_account_ref)
+ gtk_tree_row_reference_free (gas->saved_account_ref);
+ gas->saved_account_ref = NULL;
+ gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1);
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER(fmodel));
}
static void
@@ -512,7 +501,7 @@ toggle_placeholder_cb (GtkWidget *widget, gpointer user_data)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
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
@@ -520,7 +509,7 @@ toggle_hidden_cb (GtkWidget *widget, gpointer user_data)
{
GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
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
@@ -551,16 +540,23 @@ icon_release_cb (GtkEntry *entry, GtkEntryIconPosition icon_pos,
gtk_menu_popup_at_pointer (GTK_MENU(menu), (GdkEvent *)event);
}
-/* An account is included if gas->acctTypeFilters or gas->acctCommodityFilters is populated
- * and the account is in the list (both lists if both are populated).
+/* An account is included if gas->acctTypeFilters or gas->acctCommodityFilters
+ * 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
account_is_included (GNCAccountSel *gas, Account *acc)
{
gboolean included = TRUE;
+ if (gas->acctExcludeList)
+ {
+ if (g_list_find (gas->acctExcludeList, acc) != NULL)
+ included = FALSE;
+ }
+
/* Filter as we've been configured to do. */
if (gas->acctTypeFilters)
{
@@ -586,33 +582,134 @@ account_is_included (GNCAccountSel *gas, Account *acc)
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
gnc_account_sel_init (GNCAccountSel *gas)
{
GtkWidget *widget;
GtkWidget *entry;
GtkEntryCompletion *completion;
+ Account *root = gnc_get_current_root_account ();
+ GtkTreeModel *filter_model;
gtk_orientable_set_orientation (GTK_ORIENTABLE(gas), GTK_ORIENTATION_HORIZONTAL);
- gas->initDone = FALSE;
- gas->acctTypeFilters = FALSE;
+ gas->acctTypeFilters = NULL;
+ gas->acctCommodityFilters = NULL;
+ gas->acctExcludeList = NULL;
gas->newAccountButton = NULL;
- gas->currentSelection = -1;
gas->hide_placeholder = 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);
// 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");
- gas->store = gtk_list_store_new (NUM_ACCT_COLS, G_TYPE_STRING, G_TYPE_POINTER);
- widget = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL(gas->store));
+ // We are just using the quickfill list store which will be the same for all
+ 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);
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);
// set the default horizontal expansion to TRUE
@@ -636,105 +733,18 @@ gnc_account_sel_init (GNCAccountSel *gas)
(GtkEntryCompletionMatchFunc)completion_function,
gas, NULL);
- /* Get the accounts, place into combo list */
- gas_populate_list (gas);
+ // Set default entry to none and blank entry
+ gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1);
+ gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
- // set sort order
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(gas->store),
- ACCT_COL_NAME, GTK_SORT_ASCENDING);
+ gas->row_deleted_id = g_signal_connect (G_OBJECT(gas->store), "row-deleted",
+ G_CALLBACK(row_has_been_deleted_in_store_cb), gas);
- gas->eventHandlerId =
- qof_event_register_handler (gnc_account_sel_event_cb, gas);
+ gas->row_changed_id = g_signal_connect (G_OBJECT(gas->store), "row-changed",
+ G_CALLBACK(row_has_been_changed_in_store_cb), gas);
- gas->initDone = TRUE;
-}
-
-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);
+ g_signal_connect_swapped (gas->combo, "changed",
+ G_CALLBACK(combo_changed_cb), gas);
}
GtkWidget *
@@ -752,14 +762,14 @@ typedef struct
} gas_find_data;
static gboolean
-gnc_account_sel_find_account (GtkTreeModel *model,
+gnc_account_sel_find_account (GtkTreeModel *fmodel,
GtkTreePath *path,
GtkTreeIter *iter,
gas_find_data *data)
{
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)
return FALSE;
@@ -771,7 +781,7 @@ gnc_account_sel_find_account (GtkTreeModel *model,
* and hide_hidden accordingly to show it.
*/
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 included = account_is_included (gas, acct);
@@ -793,7 +803,7 @@ check_account_can_be_seen (GNCAccountSel *gas, Account *acct)
changed = TRUE;
}
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,
gboolean set_default_acct)
{
+ GtkTreeModel *fmodel;
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)
- check_account_can_be_seen (gas, acct);
+ check_account_can_be_seen (gas, fmodel, acct);
if (set_default_acct)
{
@@ -824,7 +840,7 @@ gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
}
data.gas = gas;
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,
&data);
}
@@ -832,15 +848,24 @@ gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
Account*
gnc_account_sel_get_account (GNCAccountSel *gas)
{
+ GtkTreeModel *fmodel;
+ GtkTreeIter fiter;
GtkTreeIter iter;
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;
+ 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,
- ACCT_COL_PTR, &acc,
- -1);
+ ACCT_COL_PTR, &acc, -1);
return acc;
}
@@ -848,6 +873,8 @@ void
gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters,
GList *commodityFilters)
{
+ g_return_if_fail (gas != NULL);
+ g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
if (gas->acctTypeFilters != NULL)
{
@@ -861,10 +888,6 @@ gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters,
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
* ints-casted-as-pointers. */
if (typeFilters)
@@ -874,7 +897,27 @@ gnc_account_sel_set_acct_filters (GNCAccountSel *gas, GList *typeFilters,
if (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
@@ -893,6 +936,9 @@ gnc_account_sel_finalize (GObject *object)
if (gas->acctCommodityFilters)
g_list_free (gas->acctCommodityFilters);
+ if (gas->acctExcludeList)
+ g_list_free (gas->acctExcludeList);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -906,17 +952,17 @@ gnc_account_sel_dispose (GObject *object)
gas = GNC_ACCOUNT_SEL(object);
- if (gas->store)
- {
- g_object_unref (gas->store);
- gas->store = NULL;
- }
+ if (gas->row_changed_id > 0)
+ g_signal_handler_disconnect (G_OBJECT(gas->store), gas->row_changed_id);
+ gas->row_changed_id = 0;
- if (gas->eventHandlerId)
- {
- qof_event_unregister_handler (gas->eventHandlerId);
- gas->eventHandlerId = 0;
- }
+ if (gas->row_deleted_id > 0)
+ g_signal_handler_disconnect (G_OBJECT(gas->store), gas->row_deleted_id);
+ gas->row_deleted_id = 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);
}
@@ -926,6 +972,7 @@ gnc_account_sel_set_new_account_ability (GNCAccountSel *gas,
gboolean state)
{
g_return_if_fail (gas != NULL);
+ g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
if (state == (gas->newAccountButton != NULL))
{
@@ -959,19 +1006,21 @@ gnc_account_sel_set_new_account_modal (GNCAccountSel *gas,
gboolean state)
{
g_return_if_fail (gas != NULL);
+ g_return_if_fail (GNC_IS_ACCOUNT_SEL(gas));
+
gas->isModal = state;
}
static void
-gas_new_account_click (GtkButton *b, gpointer ud)
+gas_new_account_click (GtkButton *b, gpointer user_data)
{
- GNCAccountSel *gas = (GNCAccountSel*)ud;
- Account *account = NULL;
+ GNCAccountSel *gas = (GNCAccountSel*)user_data;
GtkWindow *parent = GTK_WINDOW(gtk_widget_get_toplevel (GTK_WIDGET(gas)));
+
if (gas->isModal)
{
- account = gnc_ui_new_accounts_from_name_window_with_types (parent, NULL,
- gas->acctTypeFilters);
+ Account *account = gnc_ui_new_accounts_from_name_window_with_types (parent, NULL,
+ gas->acctTypeFilters);
if (account)
gnc_account_sel_set_account (gas, account, FALSE);
}
@@ -981,58 +1030,14 @@ gas_new_account_click (GtkButton *b, gpointer ud)
}
gint
-gnc_account_sel_get_num_account (GNCAccountSel *gas)
+gnc_account_sel_get_visible_account_num (GNCAccountSel *gas)
{
- if (NULL == gas)
- return 0;
+ GtkTreeModel *fmodel;
- 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
-gnc_account_sel_purge_account (GNCAccountSel *gas,
- Account *target,
- 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);
- }
+ fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
- 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);
+ return gtk_tree_model_iter_n_children (fmodel, NULL);
}
diff --git a/gnucash/gnome-utils/gnc-account-sel.h b/gnucash/gnome-utils/gnc-account-sel.h
index ec6a2019c..3820a8969 100644
--- a/gnucash/gnome-utils/gnc-account-sel.h
+++ b/gnucash/gnome-utils/gnc-account-sel.h
@@ -48,7 +48,7 @@ typedef struct
void (*account_sel_changed) (GNCAccountSel *gas);
} GNCAccountSelClass;
-GType gnc_account_sel_get_type (void);
+GType gnc_account_sel_get_type (void) G_GNUC_CONST;
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
* NULL, then the first list selection is made if set_default_acct is TRUE.
**/
-void gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
- gboolean set_default_acct);
+void gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
+ gboolean set_default_acct);
+
/**
* Returns the currently-selected Account. If, for some reason the selection
* 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.
@@ -70,9 +71,19 @@ Account* gnc_account_sel_get_account (GNCAccountSel *gas);
* @param commodityFilters A GList of gnc_commodity types which are allowed.
* 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);
+/**
+ * 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
* 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);
-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 */
diff --git a/gnucash/gnome/gnc-plugin-page-account-tree.c b/gnucash/gnome/gnc-plugin-page-account-tree.c
index 94d3293dc..7fb33fb4b 100644
--- a/gnucash/gnome/gnc-plugin-page-account-tree.c
+++ b/gnucash/gnome/gnc-plugin-page-account-tree.c
@@ -1316,8 +1316,8 @@ set_ok_sensitivity(GtkWidget *dialog)
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);
- sa_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(sa_mas));
- trans_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(trans_mas));
+ sa_mas_cnt = gnc_account_sel_get_visible_account_num(GNC_ACCOUNT_SEL(sa_mas));
+ trans_mas_cnt = gnc_account_sel_get_visible_account_num(GNC_ACCOUNT_SEL(trans_mas));
sensitive = (((NULL == sa_mas) ||
(!gtk_widget_is_sensitive(sa_mas) || sa_mas_cnt)) &&
@@ -1328,6 +1328,19 @@ set_ok_sensitivity(GtkWidget *dialog)
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
gppat_populate_gas_list(GtkWidget *dialog,
GNCAccountSel *gas,
@@ -1335,6 +1348,7 @@ gppat_populate_gas_list(GtkWidget *dialog,
{
Account *account;
GList *filter;
+ GList *exclude;
g_return_if_fail(GTK_IS_DIALOG(dialog));
if (gas == NULL)
@@ -1345,8 +1359,12 @@ gppat_populate_gas_list(GtkWidget *dialog,
/* Setting the account type filter triggers GNCAccountSel population. */
gnc_account_sel_set_acct_filters (gas, filter, NULL);
- /* Accounts to be deleted must be removed. */
- gnc_account_sel_purge_account( gas, account, exclude_subaccounts);
+ /* Accounts to be deleted must be excluded from GAS. */
+ 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. */
set_ok_sensitivity(dialog);
commit e21162663842e35970cc10bd4495e701920ef1eb
Author: Robert Fewell <14uBobIT at gmail.com>
Date: Tue Sep 20 12:42:52 2022 +0100
Add an entry width property to GNCAccountSel widget
Add a property to GNCAccountSel widget so that you can specify the
entry width. This can be used to specify the width of the GAS when you
do not want it to take up all the space available.
diff --git a/gnucash/gnome-utils/gnc-account-sel.c b/gnucash/gnome-utils/gnc-account-sel.c
index 0b9dd31af..950712d66 100644
--- a/gnucash/gnome-utils/gnc-account-sel.c
+++ b/gnucash/gnome-utils/gnc-account-sel.c
@@ -80,6 +80,7 @@ enum
PROP_HIDE_PLACEHOLDER,
PROP_HIDE_HIDDEN,
PROP_HORIZONTAL_EXPAND,
+ PROP_COMBO_ENTRY_WIDTH,
};
static guint account_sel_signals [LAST_SIGNAL] = { 0 };
@@ -176,6 +177,23 @@ gas_set_property (GObject *object, guint param_id,
gtk_widget_set_hexpand (GTK_WIDGET(gas->combo), g_value_get_boolean (value));
break;
+ case PROP_COMBO_ENTRY_WIDTH:
+ {
+ GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
+ gboolean expand = FALSE;
+ gint width = g_value_get_int (value);
+
+ if (width == -1)
+ expand = TRUE;
+
+ gtk_widget_set_hexpand (GTK_WIDGET(gas), expand);
+ gtk_widget_set_hexpand (GTK_WIDGET(gas->combo), expand);
+
+ gtk_entry_set_width_chars (entry, width);
+ gtk_widget_queue_resize (GTK_WIDGET(gas));
+ }
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
@@ -207,6 +225,13 @@ gas_get_property (GObject *object, guint param_id,
g_value_set_boolean (value, gtk_widget_get_hexpand (GTK_WIDGET(gas)));
break;
+ case PROP_COMBO_ENTRY_WIDTH:
+ {
+ GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
+ g_value_set_int (value, gtk_entry_get_width_chars (entry));
+ }
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
@@ -244,6 +269,12 @@ gnc_account_sel_class_init (GNCAccountSelClass *klass)
"Should GAS take all horizontal space", TRUE,
G_PARAM_READWRITE));
+ g_object_class_install_property(
+ object_class, PROP_COMBO_ENTRY_WIDTH,
+ g_param_spec_int("entry-width", "Number of Charactors",
+ "Set the width of the combo entry",
+ -1, 100, -1, G_PARAM_READWRITE));
+
account_sel_signals [ACCOUNT_SEL_CHANGED] =
g_signal_new ("account_sel_changed",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/gnucash/gnome/assistant-loan.cpp b/gnucash/gnome/assistant-loan.cpp
index ebf6c6257..4e7cfbe59 100644
--- a/gnucash/gnome/assistant-loan.cpp
+++ b/gnucash/gnome/assistant-loan.cpp
@@ -734,6 +734,7 @@ gnc_loan_assistant_create( LoanAssistantData *ldd )
G_CALLBACK(loan_opt_escrow_toggle_cb), ldd );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), FALSE );
ldd->optEscrowGAS = GNC_ACCOUNT_SEL(gnc_account_sel_new());
+ g_object_set (ldd->optEscrowGAS, "entry-width", 50, NULL);
gnc_account_sel_set_new_account_modal (GNC_ACCOUNT_SEL(ldd->optEscrowGAS), true);
gnc_account_sel_set_new_account_ability( ldd->optEscrowGAS, TRUE );
gtk_container_add( GTK_CONTAINER(ldd->optEscrowHBox),
commit 4d96c0d74c56aeadaeb8b600e132dbb55aed650b
Author: Robert Fewell <14uBobIT at gmail.com>
Date: Tue Sep 20 12:38:47 2022 +0100
Change GNCAccountSel horizontal expand to a property
Add a horizontal expand property to GNCAccountSel widget and set the
default expansion to TRUE.
diff --git a/gnucash/gnome-utils/dialog-book-close.c b/gnucash/gnome-utils/dialog-book-close.c
index 147ab6c0c..f6cafe4c9 100644
--- a/gnucash/gnome-utils/dialog-book-close.c
+++ b/gnucash/gnome-utils/dialog-book-close.c
@@ -351,7 +351,6 @@ void gnc_ui_close_book (QofBook* book, GtkWindow *parent)
equity_list = g_list_prepend(equity_list, GINT_TO_POINTER(ACCT_TYPE_EQUITY));
box = GTK_WIDGET(gtk_builder_get_object (builder, "income_acct_box"));
cbw->income_acct_widget = gnc_account_sel_new();
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(cbw->income_acct_widget), TRUE);
gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->income_acct_widget),
equity_list, NULL);
gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->income_acct_widget), TRUE);
@@ -360,7 +359,6 @@ void gnc_ui_close_book (QofBook* book, GtkWindow *parent)
/* expense acct */
box = GTK_WIDGET(gtk_builder_get_object (builder, "expense_acct_box"));
cbw->expense_acct_widget = gnc_account_sel_new();
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(cbw->expense_acct_widget), TRUE);
gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(cbw->expense_acct_widget),
equity_list, NULL);
gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(cbw->expense_acct_widget), TRUE);
diff --git a/gnucash/gnome-utils/gnc-account-sel.c b/gnucash/gnome-utils/gnc-account-sel.c
index d7b00661e..0b9dd31af 100644
--- a/gnucash/gnome-utils/gnc-account-sel.c
+++ b/gnucash/gnome-utils/gnc-account-sel.c
@@ -79,6 +79,7 @@ enum
PROP_0,
PROP_HIDE_PLACEHOLDER,
PROP_HIDE_HIDDEN,
+ PROP_HORIZONTAL_EXPAND,
};
static guint account_sel_signals [LAST_SIGNAL] = { 0 };
@@ -170,6 +171,11 @@ gas_set_property (GObject *object, guint param_id,
gas->hide_hidden = g_value_get_boolean (value);
break;
+ case PROP_HORIZONTAL_EXPAND:
+ gtk_widget_set_hexpand (GTK_WIDGET(gas), g_value_get_boolean (value));
+ gtk_widget_set_hexpand (GTK_WIDGET(gas->combo), g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
@@ -197,6 +203,10 @@ gas_get_property (GObject *object, guint param_id,
g_value_set_boolean (value, gas->hide_hidden);
break;
+ case PROP_HORIZONTAL_EXPAND:
+ g_value_set_boolean (value, gtk_widget_get_hexpand (GTK_WIDGET(gas)));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
@@ -228,6 +238,12 @@ gnc_account_sel_class_init (GNCAccountSelClass *klass)
"Hidden accounts are hidden", TRUE,
G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class, PROP_HIDE_HIDDEN,
+ g_param_spec_boolean("horizontal-expand", "Horizontal Expand",
+ "Should GAS take all horizontal space", TRUE,
+ G_PARAM_READWRITE));
+
account_sel_signals [ACCOUNT_SEL_CHANGED] =
g_signal_new ("account_sel_changed",
G_OBJECT_CLASS_TYPE (object_class),
@@ -568,6 +584,10 @@ gnc_account_sel_init (GNCAccountSel *gas)
G_CALLBACK(combo_changed_cb), gas);
gtk_container_add (GTK_CONTAINER(gas), widget);
+ // set the default horizontal expansion to TRUE
+ gtk_widget_set_hexpand (GTK_WIDGET(gas), TRUE);
+ gtk_widget_set_hexpand (GTK_WIDGET(gas->combo), TRUE);
+
entry = gtk_bin_get_child (GTK_BIN(gas->combo));
gtk_entry_set_icon_from_icon_name (GTK_ENTRY(entry), GTK_ENTRY_ICON_SECONDARY,
"preferences-system-symbolic");
@@ -598,13 +618,6 @@ gnc_account_sel_init (GNCAccountSel *gas)
gas->initDone = TRUE;
}
-void
-gnc_account_sel_set_hexpand (GNCAccountSel *gas, gboolean expand)
-{
- gtk_widget_set_hexpand (GTK_WIDGET(gas), expand);
- gtk_widget_set_hexpand (GTK_WIDGET(gas->combo), expand);
-}
-
typedef struct
{
GNCAccountSel *gas;
diff --git a/gnucash/gnome-utils/gnc-account-sel.h b/gnucash/gnome-utils/gnc-account-sel.h
index 0689fb1d8..ec6a2019c 100644
--- a/gnucash/gnome-utils/gnc-account-sel.h
+++ b/gnucash/gnome-utils/gnc-account-sel.h
@@ -88,6 +88,5 @@ 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);
-void gnc_account_sel_set_hexpand (GNCAccountSel *gas, gboolean expand);
#endif /* GNC_ACCOUNT_SEL_H */
diff --git a/gnucash/gnome/assistant-loan.cpp b/gnucash/gnome/assistant-loan.cpp
index 580f9d7d5..ebf6c6257 100644
--- a/gnucash/gnome/assistant-loan.cpp
+++ b/gnucash/gnome/assistant-loan.cpp
@@ -641,7 +641,6 @@ gnc_loan_assistant_create( LoanAssistantData *ldd )
gas_data[i].height);
gtk_widget_set_halign (GTK_WIDGET(gas), GTK_ALIGN_FILL);
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(gas), true);
gnc_account_sel_set_new_account_modal (GNC_ACCOUNT_SEL(gas), true);
g_object_set (GTK_WIDGET(gas), "margin", 2, nullptr);
*(gas_data[i].loc) = gas;
@@ -735,7 +734,6 @@ gnc_loan_assistant_create( LoanAssistantData *ldd )
G_CALLBACK(loan_opt_escrow_toggle_cb), ldd );
gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), FALSE );
ldd->optEscrowGAS = GNC_ACCOUNT_SEL(gnc_account_sel_new());
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(ldd->optEscrowGAS), true);
gnc_account_sel_set_new_account_modal (GNC_ACCOUNT_SEL(ldd->optEscrowGAS), true);
gnc_account_sel_set_new_account_ability( ldd->optEscrowGAS, TRUE );
gtk_container_add( GTK_CONTAINER(ldd->optEscrowHBox),
diff --git a/gnucash/gnome/dialog-date-close.c b/gnucash/gnome/dialog-date-close.c
index 83f6e44fe..a6b5f5e49 100644
--- a/gnucash/gnome/dialog-date-close.c
+++ b/gnucash/gnome/dialog-date-close.c
@@ -239,7 +239,6 @@ gnc_dialog_dates_acct_question_parented (GtkWidget *parent, const char *message,
acct_box = GTK_WIDGET(gtk_builder_get_object (builder, "acct_hbox"));
ddc->acct_combo = gnc_account_sel_new();
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(ddc->acct_combo), TRUE);
gtk_box_pack_start (GTK_BOX(acct_box), ddc->acct_combo, TRUE, TRUE, 0);
date_box = GTK_WIDGET(gtk_builder_get_object (builder, "date_hbox"));
@@ -360,7 +359,6 @@ gnc_dialog_date_acct_parented (GtkWidget *parent, const char *message,
ddc->acct_combo = gnc_account_sel_new();
if (*acct)
gnc_account_sel_set_account (GNC_ACCOUNT_SEL(ddc->acct_combo), *acct, FALSE);
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(ddc->acct_combo), TRUE);
gtk_box_pack_start (GTK_BOX(acct_box), ddc->acct_combo, TRUE, TRUE, 0);
date_box = GTK_WIDGET(gtk_builder_get_object (builder, "date_hbox"));
diff --git a/gnucash/gnome/dialog-employee.c b/gnucash/gnome/dialog-employee.c
index e4f02dfa1..71a841232 100644
--- a/gnucash/gnome/dialog-employee.c
+++ b/gnucash/gnome/dialog-employee.c
@@ -479,7 +479,6 @@ gnc_employee_new_window (GtkWindow *parent,
edit = gnc_account_sel_new();
acct_types = g_list_prepend(NULL, (gpointer)ACCT_TYPE_CREDIT);
gnc_account_sel_set_acct_filters (GNC_ACCOUNT_SEL(edit), acct_types, NULL);
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(edit), TRUE);
g_list_free (acct_types);
ew->ccard_acct_sel = edit;
diff --git a/gnucash/gnome/gnc-plugin-page-account-tree.c b/gnucash/gnome/gnc-plugin-page-account-tree.c
index 30370aa52..94d3293dc 100644
--- a/gnucash/gnome/gnc-plugin-page-account-tree.c
+++ b/gnucash/gnome/gnc-plugin-page-account-tree.c
@@ -1397,7 +1397,6 @@ gppat_setup_account_selector (GtkBuilder *builder, GtkWidget *dialog,
GtkWidget *box = GTK_WIDGET(gtk_builder_get_object (builder, hbox));
gtk_box_pack_start (GTK_BOX(box), selector, TRUE, TRUE, 0);
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(selector), TRUE);
// placeholder accounts are OK for this GAS
if (g_strcmp0 (sel_name, DELETE_DIALOG_SA_MAS) == 0)
diff --git a/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp
index 07d1cb1d0..3c154facd 100644
--- a/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp
+++ b/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp
@@ -572,7 +572,6 @@ CsvImpTransAssist::CsvImpTransAssist ()
acct_selector = gnc_account_sel_new();
auto account_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "account_hbox"));
gtk_box_pack_start (GTK_BOX(account_hbox), acct_selector, TRUE, TRUE, 6);
- gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(acct_selector), true);
gtk_widget_show (acct_selector);
g_signal_connect(G_OBJECT(acct_selector), "account_sel_changed",
commit 13bb321c06f5c332744817013851da02db74e32f
Author: Robert Fewell <14uBobIT at gmail.com>
Date: Tue Sep 20 12:36:37 2022 +0100
Update delete sub accounts GAS
When deleting accounts and moving sub-accounts, placeholder accounts
can be used so change property of GAS accordingly.
diff --git a/gnucash/gnome/gnc-plugin-page-account-tree.c b/gnucash/gnome/gnc-plugin-page-account-tree.c
index 4bcd08dd7..30370aa52 100644
--- a/gnucash/gnome/gnc-plugin-page-account-tree.c
+++ b/gnucash/gnome/gnc-plugin-page-account-tree.c
@@ -1398,6 +1398,11 @@ gppat_setup_account_selector (GtkBuilder *builder, GtkWidget *dialog,
gtk_box_pack_start (GTK_BOX(box), selector, TRUE, TRUE, 0);
gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(selector), TRUE);
+
+ // placeholder accounts are OK for this GAS
+ if (g_strcmp0 (sel_name, DELETE_DIALOG_SA_MAS) == 0)
+ g_object_set (selector, "hide-placeholder", FALSE, NULL);
+
g_object_set_data(G_OBJECT(dialog), sel_name, selector);
gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(selector), TRUE);
commit 1d163b7f2613ab3405c0a79968b0688640125bca
Author: Robert Fewell <14uBobIT at gmail.com>
Date: Tue Sep 20 12:34:42 2022 +0100
Add ability to hide placeholder and hidden accounts to GAS
Change the GNCAccountSel widget to hide placeholder and hidden
accounts. By default these accounts are hidden, but with the use of a
secondary icon a popup menu is presented where the list can be
configured to show them. Also when the GNCAccountSel is set to a
specific account with with gnc_account_sel_set_account, the placeholder
and hidden properties are checked and appropriate changes made so the
account will be visible.
diff --git a/gnucash/gnome-utils/gnc-account-sel.c b/gnucash/gnome-utils/gnc-account-sel.c
index 90414a311..d7b00661e 100644
--- a/gnucash/gnome-utils/gnc-account-sel.c
+++ b/gnucash/gnome-utils/gnc-account-sel.c
@@ -70,6 +70,15 @@ struct _GNCAccountSel
GtkWidget *newAccountButton;
gint currentSelection;
char sep_key_prefix[BUFLEN];
+ gboolean hide_placeholder;
+ gboolean hide_hidden;
+};
+
+enum
+{
+ PROP_0,
+ PROP_HIDE_PLACEHOLDER,
+ PROP_HIDE_HIDDEN,
};
static guint account_sel_signals [LAST_SIGNAL] = { 0 };
@@ -79,6 +88,16 @@ static void gnc_account_sel_class_init (GNCAccountSelClass *klass);
static void gnc_account_sel_finalize (GObject *object);
static void gnc_account_sel_dispose (GObject *object);
+static void gas_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gas_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
static void gas_filter_accounts (gpointer data, gpointer user_data);
static void gas_populate_list (GNCAccountSel *gas);
@@ -130,6 +149,60 @@ gnc_account_sel_event_cb (QofInstance *entity,
gas_populate_list ((GNCAccountSel*)user_data);
}
+static void
+gas_set_property (GObject *object, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GNCAccountSel *gas;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNC_IS_ACCOUNT_SEL(object));
+
+ gas = GNC_ACCOUNT_SEL(object);
+
+ switch (param_id)
+ {
+ case PROP_HIDE_PLACEHOLDER:
+ gas->hide_placeholder = g_value_get_boolean (value);
+ break;
+
+ case PROP_HIDE_HIDDEN:
+ gas->hide_hidden = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gas_get_property (GObject *object, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GNCAccountSel *gas;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNC_IS_ACCOUNT_SEL(object));
+
+ gas = GNC_ACCOUNT_SEL(object);
+
+ switch (param_id)
+ {
+ case PROP_HIDE_PLACEHOLDER:
+ g_value_set_boolean (value, gas->hide_placeholder);
+ break;
+
+ case PROP_HIDE_HIDDEN:
+ g_value_set_boolean (value, gas->hide_hidden);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ break;
+ }
+}
+
static void
gnc_account_sel_class_init (GNCAccountSelClass *klass)
{
@@ -140,6 +213,21 @@ gnc_account_sel_class_init (GNCAccountSelClass *klass)
object_class->finalize = gnc_account_sel_finalize;
object_class->dispose = gnc_account_sel_dispose;
+ object_class->set_property = gas_set_property;
+ object_class->get_property = gas_get_property;
+
+ g_object_class_install_property (
+ object_class, PROP_HIDE_PLACEHOLDER,
+ g_param_spec_boolean("hide-placeholder", "Hide Placeholder",
+ "Placeholder accounts are hidden", TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class, PROP_HIDE_HIDDEN,
+ g_param_spec_boolean("hide-hidden", "Hide Hidden",
+ "Hidden accounts are hidden", TRUE,
+ G_PARAM_READWRITE));
+
account_sel_signals [ACCOUNT_SEL_CHANGED] =
g_signal_new ("account_sel_changed",
G_OBJECT_CLASS_TYPE (object_class),
@@ -359,6 +447,98 @@ entry_insert_text_cb (GtkEntry *entry, const gchar *text, gint length,
}
}
+static void
+update_entry_and_list (GNCAccountSel *gas)
+{
+ 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_entry_set_text (entry, "");
+ g_signal_handlers_unblock_by_func (gas->combo, combo_changed_cb , gas);
+
+ // refresh the account list
+ gas_populate_list (gas);
+}
+
+static void
+toggle_placeholder_cb (GtkWidget *widget, gpointer user_data)
+{
+ GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
+ gas->hide_placeholder = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget));
+ update_entry_and_list (gas);
+}
+
+static void
+toggle_hidden_cb (GtkWidget *widget, gpointer user_data)
+{
+ GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
+ gas->hide_hidden = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget));
+ update_entry_and_list (gas);
+}
+
+static void
+icon_release_cb (GtkEntry *entry, GtkEntryIconPosition icon_pos,
+ GdkEvent* event, gpointer user_data)
+{
+ GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
+ GtkWidget *menu, *h_placeholder, *h_hidden;
+
+ if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
+ return;
+
+ menu = gtk_menu_new ();
+ h_placeholder = gtk_check_menu_item_new_with_mnemonic (_("Hide _Placeholder Accounts"));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(h_placeholder), gas->hide_placeholder);
+ h_hidden = gtk_check_menu_item_new_with_mnemonic (_("Hide _Hidden Accounts"));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(h_hidden), gas->hide_hidden);
+ gtk_menu_attach_to_widget (GTK_MENU(menu), GTK_WIDGET(gas), NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu), h_placeholder);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu), h_hidden);
+ gtk_widget_show_all (menu);
+
+ g_signal_connect (G_OBJECT(h_placeholder), "toggled",
+ G_CALLBACK(toggle_placeholder_cb), gas);
+ g_signal_connect (G_OBJECT(h_hidden), "toggled",
+ G_CALLBACK(toggle_hidden_cb), gas);
+
+ gtk_menu_popup_at_pointer (GTK_MENU(menu), (GdkEvent *)event);
+}
+
+/* An account is included if gas->acctTypeFilters or gas->acctCommodityFilters is populated
+ * and the account is in the list (both lists if both are populated).
+ *
+ * If neither is populated then all accounts are included.
+ */
+static gboolean
+account_is_included (GNCAccountSel *gas, Account *acc)
+{
+ gboolean included = TRUE;
+
+ /* Filter as we've been configured to do. */
+ if (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 (gas->acctTypeFilters,
+ GINT_TO_POINTER(xaccAccountGetType (acc))) == NULL)
+ {
+ included = FALSE;
+ }
+ }
+
+ if (gas->acctCommodityFilters)
+ {
+ if (g_list_find_custom (gas->acctCommodityFilters,
+ GINT_TO_POINTER(xaccAccountGetCommodity (acc)),
+ gnc_commodity_compare_void) == NULL)
+ {
+ included = FALSE;
+ }
+ }
+ return included;
+}
+
static void
gnc_account_sel_init (GNCAccountSel *gas)
{
@@ -372,6 +552,8 @@ gnc_account_sel_init (GNCAccountSel *gas)
gas->acctTypeFilters = FALSE;
gas->newAccountButton = NULL;
gas->currentSelection = -1;
+ gas->hide_placeholder = TRUE;
+ gas->hide_hidden = TRUE;
g_object_set (gas, "spacing", 2, (gchar*)NULL);
@@ -387,6 +569,12 @@ gnc_account_sel_init (GNCAccountSel *gas)
gtk_container_add (GTK_CONTAINER(gas), widget);
entry = gtk_bin_get_child (GTK_BIN(gas->combo));
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY(entry), GTK_ENTRY_ICON_SECONDARY,
+ "preferences-system-symbolic");
+ gtk_entry_set_icon_tooltip_text (GTK_ENTRY(entry), GTK_ENTRY_ICON_SECONDARY,
+ _("Set the visibility of placeholder and hidden accounts."));
+ g_signal_connect (G_OBJECT(entry), "icon-release",
+ G_CALLBACK(icon_release_cb), gas);
g_signal_connect (G_OBJECT(entry), "insert_text",
G_CALLBACK(entry_insert_text_cb), gas);
@@ -492,30 +680,16 @@ gas_filter_accounts (gpointer data, gpointer user_data)
atnd = (account_filter_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;
- }
- }
- if (atnd->gas->acctCommodityFilters)
- {
- if (g_list_find_custom (atnd->gas->acctCommodityFilters,
- GINT_TO_POINTER(xaccAccountGetCommodity (a)),
- gnc_commodity_compare_void)
- == NULL)
- {
- return;
- }
- }
+ 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);
}
@@ -549,12 +723,45 @@ gnc_account_sel_find_account (GtkTreeModel *model,
return TRUE;
}
+/* If the account is included in the filters, set hide_placeholder
+ * and hide_hidden accordingly to show it.
+ */
+static void
+check_account_can_be_seen (GNCAccountSel *gas, Account *acct)
+{
+ gboolean changed = FALSE;
+ gboolean included = account_is_included (gas, acct);
+
+ if (included)
+ {
+ gboolean test = xaccAccountGetPlaceholder (acct);
+
+ if (test && gas->hide_placeholder == test)
+ {
+ gas->hide_placeholder = !test;
+ changed = TRUE;
+ }
+
+ test = xaccAccountIsHidden (acct);
+ if (test && gas->hide_hidden == test)
+ {
+ gas->hide_hidden = !test;
+ changed = TRUE;
+ }
+ if (changed)
+ gas_populate_list (gas);
+ }
+}
+
void
gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
gboolean set_default_acct)
{
gas_find_data data;
+ if (acct)
+ check_account_can_be_seen (gas, acct);
+
if (set_default_acct)
{
gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), 0);
commit 3b3f574c8b462e4883314f4dbb63fa107073f5dd
Author: Robert Fewell <14uBobIT at gmail.com>
Date: Sun Sep 18 14:53:48 2022 +0100
Bug 798475 - GNCAccountSel could have shortcuts
Add ability to enter e:g:t in account select entry widget which would
generate the full account path 'Expenses:Goverment:Taxes'. This is done
by an 'insert-text' callback that looks for the account separator key
being pressed. Also change the completion function so that it will
present a list of any account full paths that contain an entered search
string any where in the full path.
diff --git a/gnucash/gnome-utils/gnc-account-sel.c b/gnucash/gnome-utils/gnc-account-sel.c
index 93808e532..90414a311 100644
--- a/gnucash/gnome-utils/gnc-account-sel.c
+++ b/gnucash/gnome-utils/gnc-account-sel.c
@@ -53,6 +53,25 @@ enum account_cols
NUM_ACCT_COLS
};
+#define BUFLEN 1024
+
+struct _GNCAccountSel
+{
+ GtkBox hbox;
+ gboolean initDone;
+ gboolean isModal;
+ GtkListStore *store;
+ GtkComboBox *combo;
+ GList *acctTypeFilters;
+ GList *acctCommodityFilters;
+ 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;
+ gint currentSelection;
+ char sep_key_prefix[BUFLEN];
+};
+
static guint account_sel_signals [LAST_SIGNAL] = { 0 };
static void gnc_account_sel_init (GNCAccountSel *gas);
@@ -144,10 +163,208 @@ combo_changed_cb (GNCAccountSel *gas, gpointer combo)
g_signal_emit_by_name (gas, "account_sel_changed");
}
+static char*
+normalize_and_fold (char* utf8_string)
+{
+ char *normalized, *folded;
+ g_return_val_if_fail (utf8_string && *utf8_string, NULL);
+
+ normalized = g_utf8_normalize (utf8_string, -1, G_NORMALIZE_ALL);
+ if (!normalized)
+ return NULL;
+ folded = g_utf8_casefold (normalized, -1);
+ g_free (normalized);
+ return folded;
+}
+
+static gboolean
+completion_function (GtkEntryCompletion *completion, const char *key,
+ GtkTreeIter *iter, gpointer user_data)
+{
+ GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
+ gchar *full_name = NULL;
+ gboolean ret = FALSE;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(gas->store), iter,
+ ACCT_COL_NAME, &full_name, -1);
+
+ if (full_name && *full_name)
+ {
+ gchar *fold_full_name = normalize_and_fold (full_name);
+
+ // key is normalised and casefolded
+ if (g_strrstr (fold_full_name, key) != NULL)
+ ret = TRUE;
+
+ g_free (fold_full_name);
+ }
+ g_free (full_name);
+ return ret;
+}
+
+static char*
+normalize_and_lower (char* utf8_string)
+{
+ char *normalized, *lowered;
+ g_return_val_if_fail (utf8_string && *utf8_string, NULL);
+
+ normalized = g_utf8_normalize (utf8_string, -1, G_NORMALIZE_ALL);
+ if (!normalized)
+ return NULL;
+ lowered = g_utf8_strdown (normalized, -1);
+ g_free (normalized);
+ return lowered;
+}
+
+/* Set gas->sep_key_prefix to the account_full_name or to the longest
+ * common characters in the account_full_name.
+ */
+static void
+set_prefix_from_account_name (GNCAccountSel *gas, char* account_full_name,
+ gint item_offset_to_sep_char,
+ gint *sep_key_prefix_len)
+{
+ if (item_offset_to_sep_char < *sep_key_prefix_len)
+ {
+ *sep_key_prefix_len = item_offset_to_sep_char;
+ memset (gas->sep_key_prefix, 0, BUFLEN);
+ g_utf8_strncpy (gas->sep_key_prefix, account_full_name, *sep_key_prefix_len);
+ }
+
+ if (item_offset_to_sep_char == *sep_key_prefix_len)
+ {
+ char tmp_prefix[BUFLEN];
+
+ memset (tmp_prefix, 0, BUFLEN);
+ g_utf8_strncpy (tmp_prefix, account_full_name, *sep_key_prefix_len);
+
+ if (g_strcmp0 (gas->sep_key_prefix, tmp_prefix) != 0)
+ {
+ do
+ {
+ gchar *tmp = g_strdup (gas->sep_key_prefix);
+ (*sep_key_prefix_len)--;
+
+ memset (tmp_prefix, 0, BUFLEN);
+ g_utf8_strncpy (tmp_prefix, account_full_name, *sep_key_prefix_len);
+ memset (gas->sep_key_prefix, 0, BUFLEN);
+ g_utf8_strncpy (gas->sep_key_prefix, tmp, *sep_key_prefix_len);
+ g_free (tmp);
+
+ } while (g_strcmp0 (gas->sep_key_prefix, tmp_prefix) != 0);
+ }
+ }
+}
+
+static inline gboolean
+find_next_separator (char* account_full_name,
+ gint *item_offset_to_sep_char,
+ gunichar sep_unichar)
+{
+ const char* c;
+ gunichar uc;
+ gboolean found = FALSE;
+
+ c = g_utf8_offset_to_pointer (account_full_name, *item_offset_to_sep_char);
+ (*item_offset_to_sep_char)++;
+
+ while (*c)
+ {
+ uc = g_utf8_get_char (c);
+ if (uc == sep_unichar)
+ {
+ found = TRUE;
+ break;
+ }
+ c = g_utf8_next_char (c);
+ (*item_offset_to_sep_char)++;
+ }
+ return found;
+}
+
+/* Callback for Account separator key */
+static void
+entry_insert_text_cb (GtkEntry *entry, const gchar *text, gint length,
+ gint *position, gpointer user_data)
+{
+ GNCAccountSel *gas = GNC_ACCOUNT_SEL(user_data);
+ GtkTreeModel *fmodel = gtk_combo_box_get_model (GTK_COMBO_BOX(gas->combo));
+ const gchar *sep_char = gnc_get_account_separator_string ();
+ gchar *entered_text, *lower_entered_text;
+ glong entered_len;
+ gunichar sep_unichar;
+ gint sep_key_prefix_len = G_MAXINT;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ if (g_strcmp0 (text, sep_char) != 0)
+ return;
+
+ memset (gas->sep_key_prefix, 0, BUFLEN);
+
+ entered_text = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1);
+
+ if (!(entered_text && *entered_text))
+ return;
+
+ lower_entered_text = normalize_and_lower (entered_text);
+ entered_len = g_utf8_strlen (lower_entered_text, -1); //characters
+ sep_unichar = gnc_get_account_separator ();
+
+ // Get the first item in the list
+ valid = gtk_tree_model_get_iter_first (fmodel, &iter);
+
+ // Walk through the list, reading each full name
+ while (valid)
+ {
+ gchar *account_full_name;
+
+ gtk_tree_model_get (fmodel, &iter, ACCT_COL_NAME, &account_full_name, -1);
+
+ if (account_full_name && *account_full_name)
+ {
+ gchar *lower_account_full_name = normalize_and_lower (account_full_name);
+
+ if (g_str_has_prefix (lower_account_full_name, lower_entered_text))
+ {
+ gint item_offset_to_sep_char = entered_len;
+ gboolean found = find_next_separator (account_full_name,
+ &item_offset_to_sep_char,
+ sep_unichar);
+
+ if (found)
+ set_prefix_from_account_name (gas, account_full_name,
+ item_offset_to_sep_char,
+ &sep_key_prefix_len);
+ }
+ g_free (lower_account_full_name);
+ }
+ g_free (account_full_name);
+ valid = gtk_tree_model_iter_next (fmodel, &iter);
+ }
+ if (gas->sep_key_prefix[0] == 0)
+ g_utf8_strncpy (gas->sep_key_prefix, entered_text, entered_len);
+
+ g_free (lower_entered_text);
+ g_free (entered_text);
+
+ if (gas->sep_key_prefix[0] != 0)
+ {
+ g_signal_handlers_block_by_func (GTK_EDITABLE(entry), (gpointer) entry_insert_text_cb, user_data);
+ gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
+ gtk_editable_set_position (GTK_EDITABLE(entry), 0);
+ gtk_editable_insert_text (GTK_EDITABLE(entry), gas->sep_key_prefix, -1, position);
+ g_signal_handlers_unblock_by_func (GTK_EDITABLE(entry), (gpointer) entry_insert_text_cb, user_data);
+ g_signal_stop_emission_by_name (GTK_EDITABLE(entry), "insert_text");
+ }
+}
+
static void
gnc_account_sel_init (GNCAccountSel *gas)
{
GtkWidget *widget;
+ GtkWidget *entry;
+ GtkEntryCompletion *completion;
gtk_orientable_set_orientation (GTK_ORIENTABLE(gas), GTK_ORIENTATION_HORIZONTAL);
@@ -169,12 +386,24 @@ gnc_account_sel_init (GNCAccountSel *gas)
G_CALLBACK(combo_changed_cb), gas);
gtk_container_add (GTK_CONTAINER(gas), widget);
+ entry = gtk_bin_get_child (GTK_BIN(gas->combo));
+ g_signal_connect (G_OBJECT(entry), "insert_text",
+ G_CALLBACK(entry_insert_text_cb), gas);
+
/* Add completion. */
gnc_cbwe_require_list_item (GTK_COMBO_BOX(widget));
+ completion = gtk_entry_get_completion (GTK_ENTRY(entry));
+ gtk_entry_completion_set_match_func (completion,
+ (GtkEntryCompletionMatchFunc)completion_function,
+ gas, NULL);
/* Get the accounts, place into combo list */
gas_populate_list (gas);
+ // set sort order
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(gas->store),
+ ACCT_COL_NAME, GTK_SORT_ASCENDING);
+
gas->eventHandlerId =
qof_event_register_handler (gnc_account_sel_event_cb, gas);
@@ -205,7 +434,6 @@ gas_populate_list (GNCAccountSel *gas)
gint i, active = -1;
GList *accts, *ptr;
const gchar *currentSel;
- gchar *name;
entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
currentSel = gtk_entry_get_text (entry);
@@ -226,15 +454,24 @@ gas_populate_list (GNCAccountSel *gas)
for (ptr = atnd.outList, i = 0; ptr; ptr = g_list_next(ptr), i++)
{
acc = ptr->data;
- name = gnc_account_get_full_name (acc);
- 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 (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
@@ -326,7 +563,7 @@ gnc_account_sel_set_account (GNCAccountSel *gas, Account *acct,
}
else
{
- gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1 );
+ gtk_combo_box_set_active (GTK_COMBO_BOX(gas->combo), -1);
if (!acct)
{
GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child (GTK_BIN(gas->combo)));
diff --git a/gnucash/gnome-utils/gnc-account-sel.h b/gnucash/gnome-utils/gnc-account-sel.h
index 7ec5f116f..0689fb1d8 100644
--- a/gnucash/gnome-utils/gnc-account-sel.h
+++ b/gnucash/gnome-utils/gnc-account-sel.h
@@ -38,25 +38,7 @@
#define GNC_ACCOUNT_SEL_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, GNC_TYPE_ACCOUNT_SEL, GNCAccountSelClass)
#define GNC_IS_ACCOUNT_SEL(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, GNC_TYPE_ACCOUNT_SEL)
-typedef struct
-{
- GtkBox hbox;
- gboolean initDone;
- gboolean isModal;
- GtkListStore *store;
- GtkComboBox *combo;
- GList *acctTypeFilters;
- GList *acctCommodityFilters;
- 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;
- gint currentSelection;
-
-#if 0 /* completion not implemented. */
- GCompletion *completion;
-#endif /* 0 - completion not implemented */
-} GNCAccountSel;
+typedef struct _GNCAccountSel GNCAccountSel;
typedef struct
{
Summary of changes:
gnucash/gnome-utils/dialog-book-close.c | 2 -
gnucash/gnome-utils/gnc-account-sel.c | 901 ++++++++++++++++-----
gnucash/gnome-utils/gnc-account-sel.h | 51 +-
gnucash/gnome/assistant-loan.cpp | 3 +-
gnucash/gnome/dialog-date-close.c | 2 -
gnucash/gnome/dialog-employee.c | 1 -
gnucash/gnome/gnc-plugin-page-account-tree.c | 32 +-
.../csv-imp/assistant-csv-trans-import.cpp | 1 -
8 files changed, 749 insertions(+), 244 deletions(-)
More information about the gnucash-changes
mailing list