Skip to content

Commit

Permalink
Implement look-ahead account name completion
Browse files Browse the repository at this point in the history
Fix coding style etc

Fix travis error

Fix travis error

Remove no longer needed file

Improve the case-normalization to use utf8 functions

Restore mistakenly removed line, fix NULL pointers, improve tooltips

Make search still happen when deleting characters

Fix cosmetic and coding style issues
  • Loading branch information
jeanlaroche authored and jean committed Mar 23, 2020
1 parent 6b55222 commit 4cd059c
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 52 deletions.
1 change: 1 addition & 0 deletions bindings/core-utils.i
Expand Up @@ -124,6 +124,7 @@ gchar *gnc_locale_name (void);
SET_ENUM ("GNC-PREF-DATE-BACKMONTHS");
SET_ENUM ("GNC-PREF-SHOW-LEAF-ACCT-NAMES");
SET_ENUM ("GNC-PREF-ENTER-MOVES-TO-END");
SET_ENUM ("GNC-PREF-TYPE-AHEAD-SEARCH");
SET_ENUM ("GNC-PREF-DRAW-HOR-LINES");
SET_ENUM ("GNC-PREF-DRAW-VERT-LINES");
SET_ENUM ("GNC-PREF-ALT-COLOR-BY-TRANS");
Expand Down
75 changes: 62 additions & 13 deletions gnucash/gnome-utils/account-quickfill.c
Expand Up @@ -54,6 +54,9 @@ typedef struct
QuickFill *qf;
gboolean load_list_store;
GtkListStore *list_store;
// For the type-ahead search, we need two lists, list_store contains the accounts that
// match the search. list_store_full contain the original full list of accounts.
GtkListStore *list_store_full;
QofBook *book;
Account *root;
gint listener;
Expand All @@ -75,6 +78,7 @@ shared_quickfill_destroy (QofBook *book, gpointer key, gpointer user_data)
qfb);
gnc_quickfill_destroy (qfb->qf);
g_object_unref (qfb->list_store);
g_object_unref (qfb->list_store_full);
qof_event_unregister_handler (qfb->listener);
g_free (qfb);
}
Expand Down Expand Up @@ -120,6 +124,7 @@ load_shared_qf_cb (Account *account, gpointer data)
char *name;
GtkTreeIter iter;

// A callback to disable adding the account
if (qfb->dont_add_cb)
{
gboolean skip = (qfb->dont_add_cb) (account, qfb->dont_add_data);
Expand All @@ -138,6 +143,11 @@ load_shared_qf_cb (Account *account, gpointer data)
ACCOUNT_NAME, name,
ACCOUNT_POINTER, account,
-1);
gtk_list_store_append (qfb->list_store_full, &iter);
gtk_list_store_set (qfb->list_store_full, &iter,
ACCOUNT_NAME, name,
ACCOUNT_POINTER, account,
-1);
}
g_free (name);
}
Expand All @@ -151,6 +161,7 @@ shared_quickfill_pref_changed (gpointer prefs, gchar *pref, gpointer user_data)
/* Reload the quickfill */
gnc_quickfill_purge (qfb->qf);
gtk_list_store_clear (qfb->list_store);
gtk_list_store_clear (qfb->list_store_full);
qfb->load_list_store = TRUE;
gnc_account_foreach_descendant (qfb->root, load_shared_qf_cb, qfb);
qfb->load_list_store = FALSE;
Expand All @@ -174,7 +185,9 @@ build_shared_quickfill (QofBook *book, Account *root, const char * key,
qfb->dont_add_cb = cb;
qfb->dont_add_data = data;
qfb->load_list_store = TRUE;
qfb->list_store = gtk_list_store_new (NUM_ACCOUNT_COLUMNS,
qfb->list_store = gtk_list_store_new (NUM_ACCOUNT_COLUMNS,
G_TYPE_STRING, G_TYPE_POINTER);
qfb->list_store_full = gtk_list_store_new (NUM_ACCOUNT_COLUMNS,
G_TYPE_STRING, G_TYPE_POINTER);

gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
Expand Down Expand Up @@ -231,6 +244,23 @@ gnc_get_shared_account_name_list_store (Account *root, const char * key,
return qfb->list_store;
}

GtkListStore *
gnc_get_shared_account_name_list_store_full (Account *root, const char * key,
AccountBoolCB cb, gpointer cb_data)
{
QFB *qfb;
QofBook *book;

book = gnc_account_get_book (root);
qfb = qof_book_get_data (book, key);

if (qfb)
return qfb->list_store_full;

qfb = build_shared_quickfill (book, root, key, cb, cb_data);
return qfb->list_store_full;
}

/* Since we are maintaining a 'global' quickfill list, we need to
* update it whenever the user creates a new account. So listen
* for account modification events, and add new accounts.
Expand All @@ -249,6 +279,7 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
find_data data = { 0 };
GtkTreePath *path;
GList *tmp;
gboolean valid;

if (0 == (event_type & (QOF_EVENT_MODIFY | QOF_EVENT_ADD | QOF_EVENT_REMOVE)))
return;
Expand Down Expand Up @@ -282,7 +313,7 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
* full name of all these accounts has changed. */
data.accounts = gnc_account_get_descendants (account);
data.accounts = g_list_prepend (data.accounts, account);
gtk_tree_model_foreach (GTK_TREE_MODEL(qfb->list_store),
gtk_tree_model_foreach (GTK_TREE_MODEL(qfb->list_store_full),
shared_quickfill_find_accounts, &data);

/* Update the existing items in the list store. Its possible
Expand All @@ -294,21 +325,22 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
gchar *old_name, *new_name;
path = gtk_tree_row_reference_get_path (tmp->data);
gtk_tree_row_reference_free (tmp->data);
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL(qfb->list_store),
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL(qfb->list_store_full),
&iter, path))
{
gtk_tree_path_free (path);
continue;
}
gtk_tree_path_free (path);
gtk_tree_model_get (GTK_TREE_MODEL(qfb->list_store), &iter,
gtk_tree_model_get (GTK_TREE_MODEL(qfb->list_store_full), &iter,
ACCOUNT_POINTER, &account,
ACCOUNT_NAME, &old_name,
-1);

new_name = gnc_get_account_name_for_register (account);

/* check if the name has changed */

match = gnc_quickfill_get_string_match (qf, old_name);
if (match && (g_strcmp0 (old_name, new_name) != 0))
gnc_quickfill_remove (qf, old_name, QUICKFILL_ALPHA);
Expand All @@ -317,12 +349,12 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
qfb->dont_add_cb (account, qfb->dont_add_data))
{
gnc_quickfill_remove (qf, new_name, QUICKFILL_ALPHA);
gtk_list_store_remove (qfb->list_store, &iter);
gtk_list_store_remove (qfb->list_store_full, &iter);
}
else
{
gnc_quickfill_insert (qf, new_name, QUICKFILL_ALPHA);
gtk_list_store_set (qfb->list_store, &iter,
gtk_list_store_set (qfb->list_store_full, &iter,
ACCOUNT_NAME, new_name,
-1);
}
Expand All @@ -344,8 +376,8 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
}
}
gnc_quickfill_insert (qf, name, QUICKFILL_ALPHA);
gtk_list_store_append (qfb->list_store, &iter);
gtk_list_store_set (qfb->list_store, &iter,
gtk_list_store_append (qfb->list_store_full, &iter);
gtk_list_store_set (qfb->list_store_full, &iter,
ACCOUNT_NAME, name,
ACCOUNT_POINTER, account,
-1);
Expand All @@ -360,18 +392,18 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,

/* Does the account exist in the model? */
data.accounts = g_list_append (NULL, account);
gtk_tree_model_foreach (GTK_TREE_MODEL(qfb->list_store),
gtk_tree_model_foreach (GTK_TREE_MODEL(qfb->list_store_full),
shared_quickfill_find_accounts, &data);

/* Remove from list store */
for (tmp = data.refs; tmp; tmp = g_list_next (tmp))
{
path = gtk_tree_row_reference_get_path (tmp->data);
gtk_tree_row_reference_free (tmp->data);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL(qfb->list_store),
if (gtk_tree_model_get_iter (GTK_TREE_MODEL(qfb->list_store_full),
&iter, path))
{
gtk_list_store_remove (qfb->list_store, &iter);
gtk_list_store_remove (qfb->list_store_full, &iter);
}
gtk_tree_path_free (path);
}
Expand All @@ -384,6 +416,7 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
qfb->dont_add_cb (account, qfb->dont_add_data))
break;


match = gnc_quickfill_get_string_match (qf, name);
if (match)
{
Expand All @@ -397,8 +430,8 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,

PINFO ("insert new account %s into qf=%p", name, qf);
gnc_quickfill_insert (qf, name, QUICKFILL_ALPHA);
gtk_list_store_append (qfb->list_store, &iter);
gtk_list_store_set (qfb->list_store, &iter,
gtk_list_store_append (qfb->list_store_full, &iter);
gtk_list_store_set (qfb->list_store_full, &iter,
ACCOUNT_NAME, name,
ACCOUNT_POINTER, account,
-1);
Expand All @@ -408,6 +441,22 @@ listen_for_account_events (QofInstance *entity, QofEventId event_type,
DEBUG("other %s", name);
break;
}
/* Now that qfb->list_store_full has been updated, qfb->list_store also needs to be updated in
case we're using the regular search. */
gtk_list_store_clear(qfb->list_store);

g_debug("Replicate shared_store_full\n");
valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(qfb->list_store_full), &iter);
while (valid)
{
gchar *str_data = NULL;
GtkTreeIter iter2;
gtk_tree_model_get (GTK_TREE_MODEL(qfb->list_store_full), &iter,0, &str_data,-1);
gtk_list_store_append(qfb->list_store, &iter2);
gtk_list_store_set(qfb->list_store, &iter2, 0, str_data, -1);
valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(qfb->list_store_full), &iter);
g_free(str_data);
}

if (data.accounts)
g_list_free (data.accounts);
Expand Down
3 changes: 3 additions & 0 deletions gnucash/gnome-utils/account-quickfill.h
Expand Up @@ -74,6 +74,9 @@ gnc_get_shared_account_name_quickfill (Account *root, const char * key,
GtkListStore *
gnc_get_shared_account_name_list_store (Account *root, const char * key,
AccountBoolCB cb, gpointer cb_data);
GtkListStore *
gnc_get_shared_account_name_list_store_full (Account *root, const char * key,
AccountBoolCB cb, gpointer cb_data);

#endif

Expand Down
5 changes: 5 additions & 0 deletions gnucash/gschemas/org.gnucash.gschema.xml.in
Expand Up @@ -245,6 +245,11 @@
<summary>"Enter" key moves to bottom of register</summary>
<description>If active, pressing the enter key will move to the bottom of the register. Otherwise pressing the enter key will move to the next transaction line.</description>
</key>
<key name="type-ahead-search" type="b">
<default>false</default>
<summary>Ues type-ahead search</summary>
<description>If active, account name completion matches any substring of the account name.</description>
</key>
<key name="auto-raise-lists" type="b">
<default>true</default>
<summary>Automatically raise the list of accounts or actions during input</summary>
Expand Down

0 comments on commit 4cd059c

Please sign in to comment.