Improve the performance of the listen_for_accounts function. Never

rebuild the list_store from scratch as the time required to sort each
account insertion takes forever with a large number of accounts.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13778 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
David Hampton 2006-04-14 05:36:42 +00:00
parent 5f3491f7d3
commit 5d4b4c7b22
2 changed files with 82 additions and 67 deletions

View File

@ -1,5 +1,10 @@
2006-04-13 David Hampton <hampton@employees.org> 2006-04-13 David Hampton <hampton@employees.org>
* src/gnome-utils/account-quickfill.c: Improve the performance of
the listen_for_accounts function. Never rebuild the list_store
from scratch as the time required to sort each account insertion
takes forever with a large number of accounts.
* src/gnome-utils/window-main-summarybar.c: * src/gnome-utils/window-main-summarybar.c:
* src/gnome/dialog-commodities.c: * src/gnome/dialog-commodities.c:
* src/engine/engine.scm: * src/engine/engine.scm:

View File

@ -75,24 +75,31 @@ shared_quickfill_destroy (QofBook *book, gpointer key, gpointer user_data)
typedef struct find_data { typedef struct find_data {
Account *account; GList *accounts;
GtkTreePath *found; GList *refs;
} find_data; } find_data;
static gboolean static gboolean
shared_quickfill_find_account (GtkTreeModel *model, shared_quickfill_find_accounts (GtkTreeModel *model,
GtkTreePath *path, GtkTreePath *path,
GtkTreeIter *iter, GtkTreeIter *iter,
gpointer user_data) gpointer user_data)
{ {
Account *account = NULL; Account *account = NULL;
find_data *data = user_data; find_data *data = user_data;
GtkTreeRowReference* ref;
GList *tmp;
gtk_tree_model_get(model, iter, ACCOUNT_POINTER, &account, -1); gtk_tree_model_get(model, iter, ACCOUNT_POINTER, &account, -1);
if (data->account == account) { for (tmp = data->accounts; tmp; tmp = g_list_next(tmp)) {
data->found = gtk_tree_path_copy(path); if (tmp->data == account) {
return TRUE; ref = gtk_tree_row_reference_new(model, path);
data->refs = g_list_append(data->refs, ref);
data->accounts = g_list_remove_link(data->accounts, tmp);
return (data->accounts == NULL);
}
} }
return FALSE; return FALSE;
} }
@ -224,8 +231,9 @@ listen_for_account_events (QofEntity *entity, QofEventId event_type,
const char *match_str; const char *match_str;
Account *account; Account *account;
GtkTreeIter iter; GtkTreeIter iter;
find_data data; find_data data = { 0 };
gboolean skip; GtkTreePath *path;
GList *tmp;
if (0 == (event_type & (QOF_EVENT_MODIFY | QOF_EVENT_ADD | QOF_EVENT_REMOVE))) if (0 == (event_type & (QOF_EVENT_MODIFY | QOF_EVENT_ADD | QOF_EVENT_REMOVE)))
return; return;
@ -248,67 +256,55 @@ listen_for_account_events (QofEntity *entity, QofEventId event_type,
return; return;
} }
/* Does the account exist in the model? */
data.account = account;
data.found = NULL;
gtk_tree_model_foreach(GTK_TREE_MODEL(qfb->list_store),
shared_quickfill_find_account, &data);
/* Should the account exist in the model? */
if (qfb->dont_add_cb) {
skip = (qfb->dont_add_cb) (account, qfb->dont_add_data);
} else {
skip = FALSE;
}
/* Synthesize new events to make the following case statement
* simpler. */
if (event_type == QOF_EVENT_MODIFY) {
if (skip && data.found) {
DEBUG("existing account now filtered");
event_type = QOF_EVENT_REMOVE;
} else if (!skip && !data.found) {
DEBUG("existing account no longer filtered");
event_type = QOF_EVENT_ADD;
}
}
switch (event_type) { switch (event_type) {
case QOF_EVENT_MODIFY: case QOF_EVENT_MODIFY:
DEBUG("modify %s", name); DEBUG("modify %s", name);
/* Did the account name change? */ /* Find the account (and all its descendants) in the model. The
if (data.found) { * full name of all these accounts has changed. */
gchar *old_name; data.accounts = xaccAccountGetDescendants(account);
gint result; data.accounts = g_list_prepend(data.accounts, account);
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(qfb->list_store), gtk_tree_model_foreach(GTK_TREE_MODEL(qfb->list_store),
&iter, data.found)) { shared_quickfill_find_accounts, &data);
gtk_tree_model_get(GTK_TREE_MODEL(qfb->list_store), &iter,
ACCOUNT_NAME, &old_name, /* Update the existing items in the list store. Its possible
* that the change has caused an existing item to now become
* hidden, in which case it needs to be removed from the list
* store. Otherwise its a simple update of the name string. */
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),
&iter, path))
continue;
gtk_tree_model_get(GTK_TREE_MODEL(qfb->list_store), &iter,
ACCOUNT_POINTER, &account,
-1);
if (qfb->dont_add_cb &&
qfb->dont_add_cb(account, qfb->dont_add_data)) {
gtk_list_store_remove(qfb->list_store, &iter);
} else {
gtk_list_store_set(qfb->list_store, &iter,
ACCOUNT_NAME, xaccAccountGetFullName(account),
-1); -1);
result = g_utf8_collate(name, old_name);
g_free(old_name);
if (result == 0) {
/* The account name is unchanged. This routine doesn't
* care what else might have changed, so bail now. */
break;
}
} }
} }
/* Update qf */ /* Any accounts that weren't found in the tree are accounts that
gnc_quickfill_purge(qfb->qf); * were hidden but have now become visible. Add them to the list
xaccGroupForEachAccount (qfb->group, load_shared_qf_cb, qfb, TRUE); * store. */
for (tmp = data.accounts; tmp; tmp = g_list_next(tmp)) {
/* Update list store */ account = tmp->data;
if (data.found) { if (qfb->dont_add_cb) {
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(qfb->list_store), if (qfb->dont_add_cb(account, qfb->dont_add_data)) {
&iter, data.found)) { continue;
gtk_list_store_set(qfb->list_store, &iter, }
ACCOUNT_NAME, name,
ACCOUNT_POINTER, account,
-1);
} }
gtk_list_store_append (qfb->list_store, &iter);
gtk_list_store_set (qfb->list_store, &iter,
ACCOUNT_NAME, name,
ACCOUNT_POINTER, account,
-1);
} }
break; break;
@ -319,10 +315,17 @@ listen_for_account_events (QofEntity *entity, QofEventId event_type,
gnc_quickfill_purge(qfb->qf); gnc_quickfill_purge(qfb->qf);
xaccGroupForEachAccount (qfb->group, load_shared_qf_cb, qfb, TRUE); xaccGroupForEachAccount (qfb->group, load_shared_qf_cb, qfb, TRUE);
/* Does the account exist in the model? */
data.accounts = g_list_append(NULL, account);
gtk_tree_model_foreach(GTK_TREE_MODEL(qfb->list_store),
shared_quickfill_find_accounts, &data);
/* Remove from list store */ /* Remove from list store */
if (data.found) { 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),
&iter, data.found)) { &iter, path)) {
gtk_list_store_remove(qfb->list_store, &iter); gtk_list_store_remove(qfb->list_store, &iter);
} }
} }
@ -330,6 +333,10 @@ listen_for_account_events (QofEntity *entity, QofEventId event_type,
case QOF_EVENT_ADD: case QOF_EVENT_ADD:
DEBUG("add %s", name); DEBUG("add %s", name);
if (qfb->dont_add_cb &&
qfb->dont_add_cb(account, qfb->dont_add_data))
break;
match = gnc_quickfill_get_string_match (qf, name); match = gnc_quickfill_get_string_match (qf, name);
if (match) { if (match) {
match_str = gnc_quickfill_string (match); match_str = gnc_quickfill_string (match);
@ -352,8 +359,11 @@ listen_for_account_events (QofEntity *entity, QofEventId event_type,
DEBUG("other %s", name); DEBUG("other %s", name);
break; break;
} }
if (data.found)
gtk_tree_path_free(data.found); if (data.accounts)
g_list_free(data.accounts);
if (data.refs)
g_list_free(data.refs);
g_free(name); g_free(name);
LEAVE(" "); LEAVE(" ");
} }