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:
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user