Fix Imap Editor to reflect the changes in kvp paths

There were several problems that broke the Imap Editor that have been
fixed due to kvp changes. The import-map-bayes entries were being added
to the tree view based on the number token entries squared. Retrieving
import-map entries resulted in an empty list and also deleting entries
from the tree view failed.
This commit is contained in:
Robert Fewell 2018-03-29 17:32:57 +01:00
parent dfb5de91ff
commit 6c43c3afe0
6 changed files with 138 additions and 111 deletions

View File

@ -46,7 +46,7 @@
/** Enumeration for the tree-store */
enum GncImapColumn {SOURCE_FULL_ACC, SOURCE_ACCOUNT, BASED_ON, MATCH_STRING,
MAP_FULL_ACC, MAP_ACCOUNT, FULL_CATEGORY, COUNT, FILTER};
MAP_FULL_ACC, MAP_ACCOUNT, HEAD, CATEGORY, COUNT, FILTER};
typedef enum
{
@ -139,39 +139,27 @@ are_you_sure (ImapDialog *imap_dialog)
}
static void
delete_info_bayes (Account *source_account, gchar *match_string, gint depth)
delete_info_bayes (Account *source_account, gchar *head, gint depth)
{
gchar *full_category;
full_category = g_strdup_printf (IMAP_FRAME_BAYES "/%s", match_string);
gnc_account_delete_map_entry (source_account, full_category, TRUE);
full_category = g_strdup_printf (IMAP_FRAME_BAYES);
if (depth == 1) // top level, delete all below
gnc_account_delete_map_entry (source_account, full_category, FALSE);
if (depth != 1) // below top level
gnc_account_delete_map_entry (source_account, head, NULL, NULL, FALSE);
else
gnc_account_delete_map_entry (source_account, full_category, TRUE);
gnc_account_delete_all_bayes_maps (source_account);
}
static void
delete_info_nbayes (Account *source_account, gint depth)
delete_info_nbayes (Account *source_account, gchar *head,
gchar *category, gchar *match_string, gint depth)
{
gchar *full_category;
full_category = g_strdup_printf (IMAP_FRAME "/%s", IMAP_FRAME_DESC);
gnc_account_delete_map_entry (source_account, full_category, TRUE);
full_category = g_strdup_printf (IMAP_FRAME "/%s", IMAP_FRAME_MEMO);
gnc_account_delete_map_entry (source_account, full_category, TRUE);
full_category = g_strdup_printf (IMAP_FRAME "/%s", IMAP_FRAME_CSV);
gnc_account_delete_map_entry (source_account, full_category, TRUE);
full_category = g_strdup_printf (IMAP_FRAME);
if (depth == 1) // top level, delete all below
gnc_account_delete_map_entry (source_account, full_category, FALSE);
if (depth != 1) // below top level
{
gnc_account_delete_map_entry (source_account, head, category, match_string, FALSE);
gnc_account_delete_map_entry (source_account, head, category, NULL, TRUE);
}
else
gnc_account_delete_map_entry (source_account, full_category, TRUE);
gnc_account_delete_map_entry (source_account, head, category, NULL, FALSE);
gnc_account_delete_map_entry (source_account, head, NULL, NULL, TRUE);
}
static void
@ -179,13 +167,15 @@ delete_selected_row (GtkTreeModel *model, GtkTreeIter *iter, ImapDialog *imap_di
{
Account *source_account = NULL;
gchar *full_source_account;
gchar *full_category;
gchar *head;
gchar *category;
gchar *match_string;
gtk_tree_model_get (model, iter, SOURCE_ACCOUNT, &source_account, SOURCE_FULL_ACC, &full_source_account,
FULL_CATEGORY, &full_category, MATCH_STRING, &match_string, -1);
HEAD, &head, CATEGORY, &category, MATCH_STRING, &match_string, -1);
PINFO("Account is '%s', Full Category is '%s', Match String is '%s'", full_source_account, full_category, match_string);
PINFO("Account is '%s', Head is '%s', Category is '%s', Match String is '%s'",
full_source_account, head, category, match_string);
if (source_account != NULL)
{
@ -197,19 +187,23 @@ delete_selected_row (GtkTreeModel *model, GtkTreeIter *iter, ImapDialog *imap_di
depth = gtk_tree_path_get_depth (tree_path);
gtk_tree_path_free (tree_path);
gnc_account_delete_map_entry (source_account, full_category, FALSE);
if (imap_dialog->type == ONLINE)
gnc_account_delete_map_entry (source_account, head, NULL, NULL, FALSE);
if (imap_dialog->type == BAYES)
delete_info_bayes (source_account, match_string, depth);
delete_info_bayes (source_account, head, depth);
if (imap_dialog->type == NBAYES)
delete_info_nbayes (source_account, depth);
delete_info_nbayes (source_account, head, category, match_string, depth);
}
else
g_free (full_category);
g_free (match_string);
g_free (full_source_account);
if (head)
g_free (head);
if (category)
g_free (category);
if (match_string)
g_free (match_string);
if (full_source_account)
g_free (full_source_account);
}
static void
@ -239,7 +233,7 @@ gnc_imap_dialog_delete (ImapDialog *imap_dialog)
// Walk the list
for (row = g_list_first (list); row; row = g_list_next (row))
{
if (gtk_tree_model_get_iter (model, &iter, row->data))
if (gtk_tree_model_get_iter (model, &iter, row->data))
delete_selected_row (model, &iter, imap_dialog);
}
g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
@ -413,14 +407,15 @@ add_to_store (GtkTreeModel *model, GtkTreeIter *iter, const gchar *text, GncImap
else
map_fullname = gnc_account_get_full_name (imapInfo->map_account);
PINFO("Add to Store: Source Acc '%s', Match '%s', Map Acc '%s'", fullname, imapInfo->match_string, map_fullname);
PINFO("Add to Store: Source Acc '%s', Head is '%s', Category is '%s', Match '%s', Map Acc '%s', Count is %s",
fullname, imapInfo->head, imapInfo->category, imapInfo->match_string, map_fullname, imapInfo->count);
gtk_tree_store_set (GTK_TREE_STORE(model), iter,
SOURCE_FULL_ACC, fullname, SOURCE_ACCOUNT, imapInfo->source_account,
BASED_ON, text,
MATCH_STRING, imapInfo->match_string,
MAP_FULL_ACC, map_fullname, MAP_ACCOUNT, imapInfo->map_account,
FULL_CATEGORY, imapInfo->full_category, COUNT, imapInfo->count,
HEAD, imapInfo->head, CATEGORY, imapInfo->category, COUNT, imapInfo->count,
FILTER, TRUE, -1);
g_free (fullname);
@ -433,6 +428,7 @@ get_imap_info (Account *acc, const gchar *category, GtkTreeModel *model, const g
GtkTreeIter toplevel, child;
GList *imap_list, *node;
gchar *acc_name = NULL;
gchar *head = NULL;
acc_name = gnc_account_get_full_name (acc);
PINFO("Source Acc '%s', Based on '%s', Path Head '%s'", acc_name, text, category);
@ -442,6 +438,11 @@ get_imap_info (Account *acc, const gchar *category, GtkTreeModel *model, const g
else
imap_list = gnc_account_imap_get_info (acc, category);
if (category == NULL)
head = IMAP_FRAME_BAYES;
else
head = IMAP_FRAME;
if (g_list_length (imap_list) > 0)
{
PINFO("List length is %d", g_list_length (imap_list));
@ -449,7 +450,8 @@ get_imap_info (Account *acc, const gchar *category, GtkTreeModel *model, const g
// Add top level entry of Source full Account and Based on.
gtk_tree_store_append (GTK_TREE_STORE(model), &toplevel, NULL);
gtk_tree_store_set (GTK_TREE_STORE(model), &toplevel,
SOURCE_ACCOUNT, acc, SOURCE_FULL_ACC, acc_name, BASED_ON, text, FILTER, TRUE, -1);
SOURCE_ACCOUNT, acc, SOURCE_FULL_ACC, acc_name,
HEAD, head, CATEGORY, category, BASED_ON, text, FILTER, TRUE, -1);
for (node = imap_list; node; node = g_list_next (node))
{
@ -460,8 +462,8 @@ get_imap_info (Account *acc, const gchar *category, GtkTreeModel *model, const g
add_to_store (model, &child, text, imapInfo);
// Free the members and structure
g_free (imapInfo->category_head);
g_free (imapInfo->full_category);
g_free (imapInfo->head);
g_free (imapInfo->category);
g_free (imapInfo->match_string);
g_free (imapInfo->count);
g_free (imapInfo);
@ -541,10 +543,10 @@ get_account_info_online (GList *accts, GtkTreeModel *model)
// Save source account
imapInfo.source_account = acc;
imapInfo.head = "online_id";
imapInfo.category = " ";
imapInfo.full_category = "online_id";
text = gnc_account_get_map_entry (acc, imapInfo.full_category);
text = gnc_account_get_map_entry (acc, imapInfo.head);
if (text != NULL)
{

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkTreeStore" id="tree-store">
@ -16,7 +16,9 @@
<column type="gchararray"/>
<!-- column-name map_account -->
<column type="gpointer"/>
<!-- column-name full_category -->
<!-- column-name head -->
<column type="gchararray"/>
<!-- column-name category -->
<column type="gchararray"/>
<!-- column-name count -->
<column type="gchararray"/>
@ -235,7 +237,7 @@
<property name="alignment">center</property>
</object>
<attributes>
<attribute name="text">7</attribute>
<attribute name="text">8</attribute>
</attributes>
</child>
</object>
@ -372,5 +374,8 @@
<action-widget response="-10">delete_button</action-widget>
<action-widget response="-6">close_button</action-widget>
</action-widgets>
<child>
<placeholder/>
</child>
</object>
</interface>

View File

@ -5544,7 +5544,6 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data)
return;
QofBook *book;
GncGUID *guid = NULL;
gchar *kvp_path;
gchar *guid_string = NULL;
auto imapInfo = (GncImapInfo*)user_data;
// Get the book
@ -5553,25 +5552,20 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data)
guid = (GncGUID*)g_value_get_boxed (value);
guid_string = guid_to_string (guid);
PINFO("build_non_bayes: account '%s', match account guid: '%s'",
PINFO("build_non_bayes: match string '%s', match account guid: '%s'",
(char*)key, guid_string);
kvp_path = g_strconcat (imapInfo->category_head, "/", key, NULL);
PINFO("build_non_bayes: kvp_path is '%s'", kvp_path);
auto imapInfo_node = static_cast <GncImapInfo*> (g_malloc(sizeof(GncImapInfo)));
imapInfo_node->source_account = imapInfo->source_account;
imapInfo_node->map_account = xaccAccountLookup (guid, book);
imapInfo_node->full_category = g_strdup (kvp_path);
imapInfo_node->head = g_strdup (imapInfo->head);
imapInfo_node->match_string = g_strdup (key);
imapInfo_node->category_head = g_strdup (imapInfo->category_head);
imapInfo_node->category = g_strdup (imapInfo->category);
imapInfo_node->count = g_strdup (" ");
imapInfo->list = g_list_append (imapInfo->list, imapInfo_node);
g_free (kvp_path);
g_free (guid_string);
}
@ -5589,25 +5583,19 @@ parse_bayes_imap_info (std::string const & imap_bayes_entry)
static void
build_bayes (const char *key, KvpValue * value, GncImapInfo & imapInfo)
{
auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (imapInfo.source_account), IMAP_FRAME_BAYES);
if (!slots.size()) return;
for (auto const & entry : slots)
{
auto parsed_key = parse_bayes_imap_info (entry.first);
auto temp_guid = gnc::GUID::from_string (std::get <2> (parsed_key));
GncGUID guid = temp_guid;
auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
std::string category_head {std::get <0> (parsed_key) + "/" + std::get <1> (parsed_key)};
auto imap_node = static_cast <GncImapInfo*> (g_malloc (sizeof (GncImapInfo)));
auto count = entry.second->get <int64_t> ();
imap_node->source_account = imapInfo.source_account;
imap_node->map_account = map_account;
imap_node->full_category = g_strdup (key);
imap_node->match_string = g_strdup (std::get <1> (parsed_key).c_str ());
imap_node->category_head = g_strdup (category_head.c_str ());
imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count);
imapInfo.list = g_list_append (imapInfo.list, imap_node);
};
auto parsed_key = parse_bayes_imap_info (key);
auto temp_guid = gnc::GUID::from_string (std::get <2> (parsed_key));
GncGUID guid = temp_guid;
auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
auto imap_node = static_cast <GncImapInfo*> (g_malloc (sizeof (GncImapInfo)));
auto count = value->get <int64_t> ();
imap_node->source_account = imapInfo.source_account;
imap_node->map_account = map_account;
imap_node->head = g_strdup (key);
imap_node->match_string = g_strdup (std::get <1> (parsed_key).c_str ());
imap_node->category = g_strdup(" ");
imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count);
imapInfo.list = g_list_append (imapInfo.list, imap_node);
}
GList *
@ -5625,22 +5613,24 @@ GList *
gnc_account_imap_get_info (Account *acc, const char *category)
{
GList *list = NULL;
gchar *category_head = NULL;
GncImapInfo imapInfo;
std::vector<std::string> path {IMAP_FRAME};
if (category)
path.emplace_back (category);
imapInfo.source_account = acc;
imapInfo.list = list;
category_head = g_strdup_printf (IMAP_FRAME "/%s", category);
imapInfo.category_head = category_head;
imapInfo.head = g_strdup (IMAP_FRAME);
imapInfo.category = g_strdup (category);
if (qof_instance_has_slot (QOF_INSTANCE(acc), category_head))
qof_instance_foreach_slot (QOF_INSTANCE(acc), category_head,
if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
{
qof_instance_foreach_slot (QOF_INSTANCE(acc), IMAP_FRAME, category,
build_non_bayes, &imapInfo);
g_free (category_head);
}
return imapInfo.list;
}
@ -5667,22 +5657,44 @@ gnc_account_get_map_entry (Account *acc, const char *full_category)
void
gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty)
gnc_account_delete_map_entry (Account *acc, char *head, char *category,
char *match_string, gboolean empty)
{
gchar *kvp_path = g_strdup (full_category);
if ((acc != NULL) && qof_instance_has_slot (QOF_INSTANCE(acc), kvp_path))
if (acc != NULL)
{
xaccAccountBeginEdit (acc);
if (empty)
qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), {kvp_path});
else
qof_instance_slot_path_delete (QOF_INSTANCE(acc), {kvp_path});
PINFO("Account is '%s', path is '%s'", xaccAccountGetName (acc), kvp_path);
qof_instance_set_dirty (QOF_INSTANCE(acc));
xaccAccountCommitEdit (acc);
std::vector<std::string> path {head};
if (category)
path.emplace_back (category);
if (match_string)
path.emplace_back (match_string);
if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
{
xaccAccountBeginEdit (acc);
if (empty)
qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), path);
else
qof_instance_slot_path_delete (QOF_INSTANCE(acc), path);
PINFO("Account is '%s', head is '%s', category is '%s', match_string is'%s'",
xaccAccountGetName (acc), head, category, match_string);
qof_instance_set_dirty (QOF_INSTANCE(acc));
xaccAccountCommitEdit (acc);
}
}
}
void
gnc_account_delete_all_bayes_maps (Account *acc)
{
if (acc != NULL)
{
auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES);
if (!slots.size()) return;
for (auto const & entry : slots)
{
qof_instance_slot_path_delete (QOF_INSTANCE (acc), {entry.first});
}
}
g_free (kvp_path);
g_free (full_category);
}
/* ================================================================ */

View File

@ -1423,8 +1423,8 @@ typedef struct imap_info
Account *source_account;
Account *map_account;
GList *list;
char *category_head;
char *full_category;
char *head;
char *category;
char *match_string;
char *count;
}GncImapInfo;
@ -1444,10 +1444,15 @@ GList *gnc_account_imap_get_info (Account *acc, const char *category);
*/
gchar *gnc_account_get_map_entry (Account *acc, const char *full_category);
/** Delete the entry for Account pointed to by full_category, if empty is TRUE then use
* delete if empty, full_category is freed
/** Delete the entry for Account pointed to by head,category and match_string,
* if empty is TRUE then use delete if empty
*/
void gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty);
void gnc_account_delete_map_entry (Account *acc, char *head, char *category,
char *match_string, gboolean empty);
/** Delete all bayes entries for Account
*/
void gnc_account_delete_all_bayes_maps (Account *acc);
/** @} */

View File

@ -155,9 +155,9 @@ void qof_instance_kvp_merge_guids (const QofInstance *target,
gboolean qof_instance_has_slot (const QofInstance *inst, const char *path);
void qof_instance_slot_delete (const QofInstance *, const char * path);
void qof_instance_slot_delete_if_empty (const QofInstance *, const char * path);
void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
void(*proc)(const char*, const GValue*, void*),
void* data);
void qof_instance_foreach_slot (const QofInstance *inst, const char *head,
const char *category, void(*proc)(const char*,
const GValue*, void*), void* data);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -1359,11 +1359,14 @@ wrap_gvalue_function (const char* key, KvpValue *val, wrap_param & param)
}
void
qof_instance_foreach_slot (const QofInstance *inst, const char* path,
void (*proc)(const char*, const GValue*, void*),
void* data)
qof_instance_foreach_slot (const QofInstance *inst, const char* head, const char* category,
void (*proc)(const char*, const GValue*, void*), void* data)
{
auto slot = inst->kvp_data->get_slot({path});
std::vector<std::string> path {head};
if (category)
path.emplace_back (category);
auto slot = inst->kvp_data->get_slot(path);
if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
return;
auto frame = slot->get<KvpFrame*>();