Merge pull request #1444 from JulienMasson/threads-sorting

mu: add an option to ignore leader when sorting childs of a thread
This commit is contained in:
Dirk-Jan C. Binnema
2020-02-10 21:58:33 +02:00
committed by GitHub
2 changed files with 78 additions and 69 deletions

View File

@ -353,36 +353,8 @@ container_cmp (MuContainer *a, MuContainer *b, MuMsgFieldId mfid)
return mu_msg_cmp (a->msg, b->msg, mfid); return mu_msg_cmp (a->msg, b->msg, mfid);
} }
static gboolean
container_is_leaf (const MuContainer *c)
{
return c->child == NULL;
}
static MuContainer*
container_max (MuContainer *a, MuContainer *b, MuMsgFieldId mfid)
{
return container_cmp (a, b, mfid) > 0 ? a : b;
}
static MuContainer*
find_sorted_tree_leader (MuContainer *root, SortFuncData *order)
{
MuContainer *last_child;
if (container_is_leaf (root))
return root;
if (!order->descending)
last_child = root->child->last;
else /* reversed order, first is last */
last_child = root->child;
return container_max (root, last_child->leader, order->mfid);
}
static int static int
sort_func_wrapper (MuContainer *a, MuContainer *b, SortFuncData *data) sort_func_root (MuContainer *a, MuContainer *b, SortFuncData *data)
{ {
if (data->descending) if (data->descending)
return container_cmp (b->leader, a->leader, data->mfid); return container_cmp (b->leader, a->leader, data->mfid);
@ -390,10 +362,56 @@ sort_func_wrapper (MuContainer *a, MuContainer *b, SortFuncData *data)
return container_cmp (a->leader, b->leader, data->mfid); return container_cmp (a->leader, b->leader, data->mfid);
} }
static int
sort_func_child (MuContainer *a, MuContainer *b, SortFuncData *data)
{
if (data->descending)
return container_cmp (a, b, data->mfid);
else
return container_cmp (b, a, data->mfid);
}
static MuContainer* static MuContainer*
container_sort_real (MuContainer *c, SortFuncData *sfdata) container_sort(MuContainer *c, GCompareDataFunc func, SortFuncData *sfdata)
{ {
GSList *lst; GSList *lst;
lst = mu_container_to_list (c);
lst = g_slist_sort_with_data (lst, func, sfdata);
c = mu_container_from_list (lst);
g_slist_free (lst);
return c;
}
static MuContainer*
container_sort_child (MuContainer *c, SortFuncData *sfdata)
{
MuContainer *cur, *leader;
if (!c)
return NULL;
/* find leader */
leader = c->leader;
for (cur = c; cur; cur = cur->next) {
if (cur->child)
cur->child = container_sort_child (cur->child, sfdata);
if (container_cmp (cur->leader, leader, sfdata->mfid) > 0)
leader = cur->leader;
}
c = container_sort(c, (GCompareDataFunc)sort_func_child, sfdata);
/* set parent's leader to the one found */
c->parent->leader = leader;
return c;
}
static MuContainer*
container_sort_root (MuContainer *c, SortFuncData *sfdata)
{
MuContainer *cur; MuContainer *cur;
if (!c) if (!c)
@ -401,19 +419,10 @@ container_sort_real (MuContainer *c, SortFuncData *sfdata)
for (cur = c; cur; cur = cur->next) { for (cur = c; cur; cur = cur->next) {
if (cur->child) if (cur->child)
cur->child = container_sort_real (cur->child, sfdata); cur->child = container_sort_child (cur->child, sfdata);
cur->leader = find_sorted_tree_leader (cur, sfdata);
} }
/* sort siblings */ return container_sort (c, (GCompareDataFunc)sort_func_root, sfdata);
lst = mu_container_to_list (c);
lst = g_slist_sort_with_data(lst,
(GCompareDataFunc)sort_func_wrapper,
sfdata);
c = mu_container_from_list (lst);
g_slist_free (lst);
return c;
} }
MuContainer* MuContainer*
@ -429,7 +438,7 @@ mu_container_sort (MuContainer *c, MuMsgFieldId mfid, gboolean descending,
g_return_val_if_fail (c, NULL); g_return_val_if_fail (c, NULL);
g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL); g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL);
return container_sort_real (c, &sfdata); return container_sort_root (c, &sfdata);
} }

View File

@ -158,9 +158,9 @@ test_mu_threads_01 (void)
const tinfo items [] = { const tinfo items [] = {
{"0", "root0@msg.id", "root0"}, {"0", "root0@msg.id", "root0"},
{"0:0", "child0.0@msg.id", "Re: child 0.0"}, {"0:0", "child0.1@msg.id", "Re: child 0.1"},
{"0:1", "child0.1@msg.id", "Re: child 0.1"}, {"0:0:0", "child0.1.0@msg.id", "Re: child 0.1.0"},
{"0:1:0", "child0.1.0@msg.id", "Re: child 0.1.0"}, {"0:1", "child0.0@msg.id", "Re: child 0.0"},
{"1", "root1@msg.id", "root1"}, {"1", "root1@msg.id", "root1"},
{"2", "root2@msg.id", "root2"}, {"2", "root2@msg.id", "root2"},
/* next one's been promoted 2.0.0 => 2.0 */ /* next one's been promoted 2.0.0 => 2.0 */
@ -169,8 +169,8 @@ test_mu_threads_01 (void)
{"3", "child3.0.0.0.0@msg.id", "Re: child 3.0.0.0"}, {"3", "child3.0.0.0.0@msg.id", "Re: child 3.0.0.0"},
/* two children of absent root 4.0 */ /* two children of absent root 4.0 */
{"4:0", "child4.0@msg.id", "Re: child 4.0"}, {"4:0", "child4.1@msg.id", "Re: child 4.1"},
{"4:1", "child4.1@msg.id", "Re: child 4.1"} {"4:1", "child4.0@msg.id", "Re: child 4.0"}
}; };
xpath = fill_database (MU_TESTMAILDIR3); xpath = fill_database (MU_TESTMAILDIR3);
@ -308,13 +308,13 @@ test_mu_threads_sort_2nd_child_promotes_thread (void)
{ "0", "A@msg.id", "A"}, { "0", "A@msg.id", "A"},
{ "1", "D@msg.id", "D"}, { "1", "D@msg.id", "D"},
{ "2", "B@msg.id", "B"}, { "2", "B@msg.id", "B"},
{ "2:0", "C@msg.id", "C"}, { "2:0", "E@msg.id", "E"},
{ "2:1", "E@msg.id", "E"}, { "2:1", "C@msg.id", "C"},
}; };
const tinfo expected_desc [] = { const tinfo expected_desc [] = {
{ "0", "B@msg.id", "B"}, { "0", "B@msg.id", "B"},
{ "0:0", "E@msg.id", "E"}, { "0:0", "C@msg.id", "C"},
{ "0:1", "C@msg.id", "C"}, { "0:1", "E@msg.id", "E"},
{ "1", "D@msg.id", "D"}, { "1", "D@msg.id", "D"},
{ "2", "A@msg.id", "A"}, { "2", "A@msg.id", "A"},
}; };
@ -334,12 +334,12 @@ test_mu_threads_sort_orphan_promotes_thread (void)
const tinfo expected_asc [] = { const tinfo expected_asc [] = {
{ "0", "A@msg.id", "A"}, { "0", "A@msg.id", "A"},
{ "1", "D@msg.id", "D"}, { "1", "D@msg.id", "D"},
{ "2:0", "C@msg.id", "C"}, { "2:0", "E@msg.id", "E"},
{ "2:1", "E@msg.id", "E"}, { "2:1", "C@msg.id", "C"},
}; };
const tinfo expected_desc [] = { const tinfo expected_desc [] = {
{ "0:0", "E@msg.id", "E"}, { "0:0", "C@msg.id", "C"},
{ "0:1", "C@msg.id", "C"}, { "0:1", "E@msg.id", "E"},
{ "1", "D@msg.id", "D"}, { "1", "D@msg.id", "D"},
{ "2", "A@msg.id", "A"}, { "2", "A@msg.id", "A"},
}; };
@ -357,16 +357,16 @@ test_mu_threads_sort_child_does_not_promote_thread (void)
const char *query = "maildir:/sort/child-does-not-promote-thread"; const char *query = "maildir:/sort/child-does-not-promote-thread";
const tinfo expected_asc [] = { const tinfo expected_asc [] = {
{ "0", "X@msg.id", "X"}, { "0", "Y@msg.id", "Y"},
{ "1", "Y@msg.id", "Y"}, { "0:0", "A@msg.id", "A"},
{ "1:0", "A@msg.id", "A"}, { "1", "X@msg.id", "X"},
{ "2", "Z@msg.id", "Z"}, { "2", "Z@msg.id", "Z"},
}; };
const tinfo expected_desc [] = { const tinfo expected_desc [] = {
{ "0", "Z@msg.id", "Z"}, { "0", "Z@msg.id", "Z"},
{ "1", "Y@msg.id", "Y"}, { "1", "X@msg.id", "X"},
{ "1:0", "A@msg.id", "A"}, { "2", "Y@msg.id", "Y"},
{ "2", "X@msg.id", "X"}, { "2:0", "A@msg.id", "A"},
}; };
check_sort_by_subject_asc (query, expected_asc, check_sort_by_subject_asc (query, expected_asc,
@ -409,19 +409,19 @@ test_mu_threads_sort_granchild_promotes_only_subthread (void)
const tinfo expected_asc [] = { const tinfo expected_asc [] = {
{ "0", "A@msg.id", "A"}, { "0", "A@msg.id", "A"},
{ "1", "B@msg.id", "B"}, { "1", "B@msg.id", "B"},
{ "1:0", "C@msg.id", "C"}, { "1:0", "E@msg.id", "E"},
{ "1:1", "E@msg.id", "E"}, { "1:1", "D@msg.id", "D"},
{ "1:2", "D@msg.id", "D"}, { "1:1:0", "F@msg.id", "F"},
{ "1:2:0", "F@msg.id", "F"}, { "1:2", "C@msg.id", "C"},
{ "2", "G@msg.id", "G"}, { "2", "G@msg.id", "G"},
}; };
const tinfo expected_desc [] = { const tinfo expected_desc [] = {
{ "0", "G@msg.id", "G"}, { "0", "G@msg.id", "G"},
{ "1", "B@msg.id", "B"}, { "1", "B@msg.id", "B"},
{ "1:0", "D@msg.id", "D"}, { "1:0", "C@msg.id", "C"},
{ "1:0:0", "F@msg.id", "F"}, { "1:1", "D@msg.id", "D"},
{ "1:1", "E@msg.id", "E"}, { "1:1:0", "F@msg.id", "F"},
{ "1:2", "C@msg.id", "C"}, { "1:2", "E@msg.id", "E"},
{ "2", "A@msg.id", "A"}, { "2", "A@msg.id", "A"},
}; };