|
|
|
@ -103,7 +103,7 @@ impl Container {
|
|
|
|
|
fn set_show_subject(&mut self, set: bool) -> () {
|
|
|
|
|
self.show_subject = set;
|
|
|
|
|
}
|
|
|
|
|
pub fn get_show_subject(&self) -> bool {
|
|
|
|
|
pub fn get_show_subject(&self) -> bool {
|
|
|
|
|
self.show_subject
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -111,18 +111,17 @@ impl Container {
|
|
|
|
|
impl PartialEq for Container {
|
|
|
|
|
fn eq(&self, other: &Container) -> bool {
|
|
|
|
|
match (self.message, other.message) {
|
|
|
|
|
(Some(s), Some(o)) => {
|
|
|
|
|
s == o
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
self.id == other.id
|
|
|
|
|
}
|
|
|
|
|
(Some(s), Some(o)) => s == o,
|
|
|
|
|
_ => self.id == other.id,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_collection(threads: &mut Vec<Container>, id_table: &mut FnvHashMap<std::string::String, usize>, collection: &mut [Envelope]) -> ()
|
|
|
|
|
{
|
|
|
|
|
fn build_collection(
|
|
|
|
|
threads: &mut Vec<Container>,
|
|
|
|
|
id_table: &mut FnvHashMap<std::string::String, usize>,
|
|
|
|
|
collection: &mut [Envelope],
|
|
|
|
|
) -> () {
|
|
|
|
|
for (i, x) in collection.iter_mut().enumerate() {
|
|
|
|
|
let x_index; /* x's index in threads */
|
|
|
|
|
let m_id = x.get_message_id_raw().to_string();
|
|
|
|
@ -142,17 +141,16 @@ fn build_collection(threads: &mut Vec<Container>, id_table: &mut FnvHashMap<std:
|
|
|
|
|
} else {
|
|
|
|
|
/* Create a new Container object holding this message */
|
|
|
|
|
x_index = threads.len();
|
|
|
|
|
threads.push(
|
|
|
|
|
Container {
|
|
|
|
|
message: Some(i),
|
|
|
|
|
id: x_index,
|
|
|
|
|
parent: None,
|
|
|
|
|
first_child: None,
|
|
|
|
|
next_sibling: None,
|
|
|
|
|
date: x.get_date(),
|
|
|
|
|
indentation: 0,
|
|
|
|
|
show_subject: true,
|
|
|
|
|
});
|
|
|
|
|
threads.push(Container {
|
|
|
|
|
message: Some(i),
|
|
|
|
|
id: x_index,
|
|
|
|
|
parent: None,
|
|
|
|
|
first_child: None,
|
|
|
|
|
next_sibling: None,
|
|
|
|
|
date: x.get_date(),
|
|
|
|
|
indentation: 0,
|
|
|
|
|
show_subject: true,
|
|
|
|
|
});
|
|
|
|
|
x.set_thread(x_index);
|
|
|
|
|
id_table.insert(m_id, x_index);
|
|
|
|
|
}
|
|
|
|
@ -173,44 +171,43 @@ fn build_collection(threads: &mut Vec<Container>, id_table: &mut FnvHashMap<std:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
iasf += 1;
|
|
|
|
|
let parent_id =
|
|
|
|
|
if id_table.contains_key(r.get_raw()) {
|
|
|
|
|
let p = id_table[r.get_raw()];
|
|
|
|
|
if !(threads[p].is_descendant(threads, &threads[curr_ref]) ||
|
|
|
|
|
threads[curr_ref].is_descendant(threads, &threads[p])) {
|
|
|
|
|
threads[curr_ref].parent = Some(p);
|
|
|
|
|
if threads[p].first_child.is_none() {
|
|
|
|
|
threads[p].first_child = Some(curr_ref);
|
|
|
|
|
} else {
|
|
|
|
|
let mut child_iter = threads[p].first_child.unwrap();
|
|
|
|
|
while threads[child_iter].next_sibling.is_some() {
|
|
|
|
|
threads[child_iter].parent = Some(p);
|
|
|
|
|
child_iter = threads[child_iter].next_sibling.unwrap();
|
|
|
|
|
}
|
|
|
|
|
threads[child_iter].next_sibling = Some(curr_ref);
|
|
|
|
|
let parent_id = if id_table.contains_key(r.get_raw()) {
|
|
|
|
|
let p = id_table[r.get_raw()];
|
|
|
|
|
if !(threads[p].is_descendant(threads, &threads[curr_ref]) ||
|
|
|
|
|
threads[curr_ref].is_descendant(threads, &threads[p]))
|
|
|
|
|
{
|
|
|
|
|
threads[curr_ref].parent = Some(p);
|
|
|
|
|
if threads[p].first_child.is_none() {
|
|
|
|
|
threads[p].first_child = Some(curr_ref);
|
|
|
|
|
} else {
|
|
|
|
|
let mut child_iter = threads[p].first_child.unwrap();
|
|
|
|
|
while threads[child_iter].next_sibling.is_some() {
|
|
|
|
|
threads[child_iter].parent = Some(p);
|
|
|
|
|
child_iter = threads[child_iter].next_sibling.unwrap();
|
|
|
|
|
}
|
|
|
|
|
threads[child_iter].next_sibling = Some(curr_ref);
|
|
|
|
|
threads[child_iter].parent = Some(p);
|
|
|
|
|
}
|
|
|
|
|
p
|
|
|
|
|
} else {
|
|
|
|
|
let idx = threads.len();
|
|
|
|
|
threads.push(
|
|
|
|
|
Container {
|
|
|
|
|
message: None,
|
|
|
|
|
id: idx,
|
|
|
|
|
parent: None,
|
|
|
|
|
first_child: Some(curr_ref),
|
|
|
|
|
next_sibling: None,
|
|
|
|
|
date: x.get_date(),
|
|
|
|
|
indentation: 0,
|
|
|
|
|
show_subject: true,
|
|
|
|
|
});
|
|
|
|
|
if threads[curr_ref].parent.is_none() {
|
|
|
|
|
threads[curr_ref].parent = Some(idx);
|
|
|
|
|
}
|
|
|
|
|
id_table.insert(r.get_raw().to_string(), idx);
|
|
|
|
|
idx
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
p
|
|
|
|
|
} else {
|
|
|
|
|
let idx = threads.len();
|
|
|
|
|
threads.push(Container {
|
|
|
|
|
message: None,
|
|
|
|
|
id: idx,
|
|
|
|
|
parent: None,
|
|
|
|
|
first_child: Some(curr_ref),
|
|
|
|
|
next_sibling: None,
|
|
|
|
|
date: x.get_date(),
|
|
|
|
|
indentation: 0,
|
|
|
|
|
show_subject: true,
|
|
|
|
|
});
|
|
|
|
|
if threads[curr_ref].parent.is_none() {
|
|
|
|
|
threads[curr_ref].parent = Some(idx);
|
|
|
|
|
}
|
|
|
|
|
id_table.insert(r.get_raw().to_string(), idx);
|
|
|
|
|
idx
|
|
|
|
|
};
|
|
|
|
|
/* update thread date */
|
|
|
|
|
let mut parent_iter = parent_id;
|
|
|
|
|
'date: loop {
|
|
|
|
@ -219,8 +216,12 @@ fn build_collection(threads: &mut Vec<Container>, id_table: &mut FnvHashMap<std:
|
|
|
|
|
p.date = x.get_date();
|
|
|
|
|
}
|
|
|
|
|
match p.parent {
|
|
|
|
|
Some(p) => { parent_iter = p; },
|
|
|
|
|
None => { break 'date; },
|
|
|
|
|
Some(p) => {
|
|
|
|
|
parent_iter = p;
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
break 'date;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
curr_ref = parent_id;
|
|
|
|
@ -229,167 +230,196 @@ fn build_collection(threads: &mut Vec<Container>, id_table: &mut FnvHashMap<std:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn build_threads(collection: &mut Vec<Envelope>, sent_folder: &Option<Result<Mailbox>>) -> (Vec<Container>, Vec<usize>) {
|
|
|
|
|
/* To reconstruct thread information from the mails we need: */
|
|
|
|
|
pub fn build_threads(
|
|
|
|
|
collection: &mut Vec<Envelope>,
|
|
|
|
|
sent_folder: &Option<Result<Mailbox>>,
|
|
|
|
|
) -> (Vec<Container>, Vec<usize>) {
|
|
|
|
|
/* To reconstruct thread information from the mails we need: */
|
|
|
|
|
|
|
|
|
|
/* a vector to hold thread members */
|
|
|
|
|
let mut threads: Vec<Container> = Vec::with_capacity((collection.len() as f64 * 1.2) as usize);
|
|
|
|
|
/* A hash table of Message IDs */
|
|
|
|
|
let mut id_table: FnvHashMap<std::string::String, usize> = FnvHashMap::with_capacity_and_hasher(collection.len(), Default::default());
|
|
|
|
|
/* a vector to hold thread members */
|
|
|
|
|
let mut threads: Vec<Container> = Vec::with_capacity((collection.len() as f64 * 1.2) as usize);
|
|
|
|
|
/* A hash table of Message IDs */
|
|
|
|
|
let mut id_table: FnvHashMap<std::string::String, usize> =
|
|
|
|
|
FnvHashMap::with_capacity_and_hasher(collection.len(), Default::default());
|
|
|
|
|
|
|
|
|
|
/* Add each message to id_table and threads, and link them together according to the
|
|
|
|
|
* References / In-Reply-To headers */
|
|
|
|
|
build_collection(&mut threads, &mut id_table, collection);
|
|
|
|
|
let mut idx = collection.len();
|
|
|
|
|
let mut tidx = threads.len();
|
|
|
|
|
/* Link messages from Sent folder if they are relevant to this folder.
|
|
|
|
|
* This means that
|
|
|
|
|
* - if a message from Sent is a reply to a message in this folder, we will
|
|
|
|
|
* add it to the threading (but not the collection; non-threading users shouldn't care
|
|
|
|
|
* about this)
|
|
|
|
|
* - if a message in this folder is a reply to a message we sent, we will add it to the
|
|
|
|
|
* threading
|
|
|
|
|
*/
|
|
|
|
|
/* Add each message to id_table and threads, and link them together according to the
|
|
|
|
|
* References / In-Reply-To headers */
|
|
|
|
|
build_collection(&mut threads, &mut id_table, collection);
|
|
|
|
|
let mut idx = collection.len();
|
|
|
|
|
let mut tidx = threads.len();
|
|
|
|
|
/* Link messages from Sent folder if they are relevant to this folder.
|
|
|
|
|
* This means that
|
|
|
|
|
* - if a message from Sent is a reply to a message in this folder, we will
|
|
|
|
|
* add it to the threading (but not the collection; non-threading users shouldn't care
|
|
|
|
|
* about this)
|
|
|
|
|
* - if a message in this folder is a reply to a message we sent, we will add it to the
|
|
|
|
|
* threading
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if let Some(ref sent_box) = *sent_folder {
|
|
|
|
|
if sent_box.is_ok() {
|
|
|
|
|
let sent_mailbox = sent_box.as_ref();
|
|
|
|
|
let sent_mailbox = sent_mailbox.unwrap();;
|
|
|
|
|
if let Some(ref sent_box) = *sent_folder {
|
|
|
|
|
if sent_box.is_ok() {
|
|
|
|
|
let sent_mailbox = sent_box.as_ref();
|
|
|
|
|
let sent_mailbox = sent_mailbox.unwrap();
|
|
|
|
|
|
|
|
|
|
for x in &sent_mailbox.collection {
|
|
|
|
|
if id_table.contains_key(x.get_message_id_raw()) ||
|
|
|
|
|
(!x.get_in_reply_to_raw().is_empty() && id_table.contains_key(x.get_in_reply_to_raw())) {
|
|
|
|
|
let mut x: Envelope = (*x).clone();
|
|
|
|
|
if id_table.contains_key(x.get_message_id_raw()) {
|
|
|
|
|
let c = id_table[x.get_message_id_raw()];
|
|
|
|
|
if threads[c].message.is_some() {
|
|
|
|
|
/* skip duplicate message-id, but this should be handled instead */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
threads[c].message = Some(idx);
|
|
|
|
|
assert!(threads[c].has_children());
|
|
|
|
|
threads[c].date = x.get_date();
|
|
|
|
|
x.set_thread(c);
|
|
|
|
|
} else if !x.get_in_reply_to_raw().is_empty() && id_table.contains_key(x.get_in_reply_to_raw()) {
|
|
|
|
|
let p = id_table[x.get_in_reply_to_raw()];
|
|
|
|
|
let c = if id_table.contains_key(x.get_message_id_raw()) {
|
|
|
|
|
id_table[x.get_message_id_raw()]
|
|
|
|
|
} else {
|
|
|
|
|
threads.push(
|
|
|
|
|
Container {
|
|
|
|
|
message: Some(idx),
|
|
|
|
|
id: tidx,
|
|
|
|
|
parent: Some(p),
|
|
|
|
|
first_child: None,
|
|
|
|
|
next_sibling: None,
|
|
|
|
|
date: x.get_date(),
|
|
|
|
|
indentation: 0,
|
|
|
|
|
show_subject: true,
|
|
|
|
|
});
|
|
|
|
|
id_table.insert(x.get_message_id_raw().to_string(), tidx);
|
|
|
|
|
x.set_thread(tidx);
|
|
|
|
|
tidx += 1;
|
|
|
|
|
tidx - 1
|
|
|
|
|
};
|
|
|
|
|
threads[c].parent = Some(p);
|
|
|
|
|
if threads[p].is_descendant(&threads, &threads[c]) ||
|
|
|
|
|
threads[c].is_descendant(&threads, &threads[p]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if threads[p].first_child.is_none() {
|
|
|
|
|
threads[p].first_child = Some(c);
|
|
|
|
|
} else {
|
|
|
|
|
let mut fc = threads[p].first_child.unwrap();
|
|
|
|
|
while threads[fc].next_sibling.is_some() {
|
|
|
|
|
threads[fc].parent = Some(p);
|
|
|
|
|
fc = threads[fc].next_sibling.unwrap();
|
|
|
|
|
}
|
|
|
|
|
threads[fc].next_sibling = Some(c);
|
|
|
|
|
threads[fc].parent = Some(p);
|
|
|
|
|
for x in &sent_mailbox.collection {
|
|
|
|
|
if id_table.contains_key(x.get_message_id_raw()) ||
|
|
|
|
|
(!x.get_in_reply_to_raw().is_empty() &&
|
|
|
|
|
id_table.contains_key(x.get_in_reply_to_raw()))
|
|
|
|
|
{
|
|
|
|
|
let mut x: Envelope = (*x).clone();
|
|
|
|
|
if id_table.contains_key(x.get_message_id_raw()) {
|
|
|
|
|
let c = id_table[x.get_message_id_raw()];
|
|
|
|
|
if threads[c].message.is_some() {
|
|
|
|
|
/* skip duplicate message-id, but this should be handled instead */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
threads[c].message = Some(idx);
|
|
|
|
|
assert!(threads[c].has_children());
|
|
|
|
|
threads[c].date = x.get_date();
|
|
|
|
|
x.set_thread(c);
|
|
|
|
|
} else if !x.get_in_reply_to_raw().is_empty() &&
|
|
|
|
|
id_table.contains_key(x.get_in_reply_to_raw())
|
|
|
|
|
{
|
|
|
|
|
let p = id_table[x.get_in_reply_to_raw()];
|
|
|
|
|
let c = if id_table.contains_key(x.get_message_id_raw()) {
|
|
|
|
|
id_table[x.get_message_id_raw()]
|
|
|
|
|
} else {
|
|
|
|
|
threads.push(Container {
|
|
|
|
|
message: Some(idx),
|
|
|
|
|
id: tidx,
|
|
|
|
|
parent: Some(p),
|
|
|
|
|
first_child: None,
|
|
|
|
|
next_sibling: None,
|
|
|
|
|
date: x.get_date(),
|
|
|
|
|
indentation: 0,
|
|
|
|
|
show_subject: true,
|
|
|
|
|
});
|
|
|
|
|
id_table.insert(x.get_message_id_raw().to_string(), tidx);
|
|
|
|
|
x.set_thread(tidx);
|
|
|
|
|
tidx += 1;
|
|
|
|
|
tidx - 1
|
|
|
|
|
};
|
|
|
|
|
threads[c].parent = Some(p);
|
|
|
|
|
if threads[p].is_descendant(&threads, &threads[c]) ||
|
|
|
|
|
threads[c].is_descendant(&threads, &threads[p])
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if threads[p].first_child.is_none() {
|
|
|
|
|
threads[p].first_child = Some(c);
|
|
|
|
|
} else {
|
|
|
|
|
let mut fc = threads[p].first_child.unwrap();
|
|
|
|
|
while threads[fc].next_sibling.is_some() {
|
|
|
|
|
threads[fc].parent = Some(p);
|
|
|
|
|
fc = threads[fc].next_sibling.unwrap();
|
|
|
|
|
}
|
|
|
|
|
threads[fc].next_sibling = Some(c);
|
|
|
|
|
threads[fc].parent = Some(p);
|
|
|
|
|
}
|
|
|
|
|
/* update thread date */
|
|
|
|
|
let mut parent_iter = p;
|
|
|
|
|
'date: loop {
|
|
|
|
|
let p = &mut threads[parent_iter];
|
|
|
|
|
if p.date < x.get_date() {
|
|
|
|
|
p.date = x.get_date();
|
|
|
|
|
}
|
|
|
|
|
match p.parent {
|
|
|
|
|
Some(p) => {
|
|
|
|
|
parent_iter = p;
|
|
|
|
|
}
|
|
|
|
|
/* update thread date */
|
|
|
|
|
let mut parent_iter = p;
|
|
|
|
|
'date: loop {
|
|
|
|
|
let p = &mut threads[parent_iter];
|
|
|
|
|
if p.date < x.get_date() {
|
|
|
|
|
p.date = x.get_date();
|
|
|
|
|
}
|
|
|
|
|
match p.parent {
|
|
|
|
|
Some(p) => { parent_iter = p; },
|
|
|
|
|
None => { break 'date; },
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
break 'date;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
collection.push(x);
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
collection.push(x);
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Walk over the elements of id_table, and gather a list of the Container objects that have
|
|
|
|
|
* no parents. These are the root messages of each thread */
|
|
|
|
|
let mut root_set = Vec::with_capacity(collection.len());
|
|
|
|
|
'root_set: for v in id_table.values() {
|
|
|
|
|
if threads[*v].parent.is_none() {
|
|
|
|
|
if !threads[*v].has_message() && threads[*v].has_children() && !threads[threads[*v].first_child.unwrap()].has_sibling() {
|
|
|
|
|
/* Do not promote the children if doing so would promote them to the root set
|
|
|
|
|
* -- unless there is only one child, in which case, do. */
|
|
|
|
|
root_set.push(threads[*v].first_child.unwrap());
|
|
|
|
|
continue 'root_set;
|
|
|
|
|
}
|
|
|
|
|
root_set.push(*v);
|
|
|
|
|
}
|
|
|
|
|
/* Walk over the elements of id_table, and gather a list of the Container objects that have
|
|
|
|
|
* no parents. These are the root messages of each thread */
|
|
|
|
|
let mut root_set = Vec::with_capacity(collection.len());
|
|
|
|
|
'root_set: for v in id_table.values() {
|
|
|
|
|
if threads[*v].parent.is_none() {
|
|
|
|
|
if !threads[*v].has_message() && threads[*v].has_children() &&
|
|
|
|
|
!threads[threads[*v].first_child.unwrap()].has_sibling()
|
|
|
|
|
{
|
|
|
|
|
/* Do not promote the children if doing so would promote them to the root set
|
|
|
|
|
* -- unless there is only one child, in which case, do. */
|
|
|
|
|
root_set.push(threads[*v].first_child.unwrap());
|
|
|
|
|
continue 'root_set;
|
|
|
|
|
}
|
|
|
|
|
root_set.push(*v);
|
|
|
|
|
}
|
|
|
|
|
root_set.sort_by(|a, b| threads[*b].date.cmp(&threads[*a].date));
|
|
|
|
|
}
|
|
|
|
|
root_set.sort_by(|a, b| threads[*b].date.cmp(&threads[*a].date));
|
|
|
|
|
|
|
|
|
|
/* Group messages together by thread in a collection so we can print them together */
|
|
|
|
|
let mut threaded_collection: Vec<usize> = Vec::with_capacity(collection.len());
|
|
|
|
|
fn build_threaded(threads: &mut Vec<Container>, indentation: usize, threaded: &mut Vec<usize>, i: usize, root_subject_idx: usize, collection: &[Envelope])
|
|
|
|
|
{
|
|
|
|
|
let thread = threads[i];
|
|
|
|
|
if threads[root_subject_idx].has_message() {
|
|
|
|
|
let root_subject = collection[threads[root_subject_idx].get_message().unwrap()].get_subject();
|
|
|
|
|
/* If the Container has no Message, but does have children, remove this container but
|
|
|
|
|
* promote its children to this level (that is, splice them in to the current child
|
|
|
|
|
* list.) */
|
|
|
|
|
if indentation > 0 && thread.has_message() {
|
|
|
|
|
let subject = collection[thread.get_message().unwrap()].get_subject();
|
|
|
|
|
if subject == root_subject || subject.starts_with("Re: ") && subject.ends_with(root_subject) {
|
|
|
|
|
threads[i].set_show_subject(false);
|
|
|
|
|
}
|
|
|
|
|
/* Group messages together by thread in a collection so we can print them together */
|
|
|
|
|
let mut threaded_collection: Vec<usize> = Vec::with_capacity(collection.len());
|
|
|
|
|
fn build_threaded(
|
|
|
|
|
threads: &mut Vec<Container>,
|
|
|
|
|
indentation: usize,
|
|
|
|
|
threaded: &mut Vec<usize>,
|
|
|
|
|
i: usize,
|
|
|
|
|
root_subject_idx: usize,
|
|
|
|
|
collection: &[Envelope],
|
|
|
|
|
) {
|
|
|
|
|
let thread = threads[i];
|
|
|
|
|
if threads[root_subject_idx].has_message() {
|
|
|
|
|
let root_subject =
|
|
|
|
|
collection[threads[root_subject_idx].get_message().unwrap()].get_subject();
|
|
|
|
|
/* If the Container has no Message, but does have children, remove this container but
|
|
|
|
|
* promote its children to this level (that is, splice them in to the current child
|
|
|
|
|
* list.) */
|
|
|
|
|
if indentation > 0 && thread.has_message() {
|
|
|
|
|
let subject = collection[thread.get_message().unwrap()].get_subject();
|
|
|
|
|
if subject == root_subject ||
|
|
|
|
|
subject.starts_with("Re: ") && subject.ends_with(root_subject)
|
|
|
|
|
{
|
|
|
|
|
threads[i].set_show_subject(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if thread.has_parent() && !threads[thread.get_parent().unwrap()].has_message() {
|
|
|
|
|
threads[i].parent = None;
|
|
|
|
|
}
|
|
|
|
|
if thread.has_parent() && !threads[thread.get_parent().unwrap()].has_message() {
|
|
|
|
|
threads[i].parent = None;
|
|
|
|
|
}
|
|
|
|
|
let indentation = if thread.has_message() {
|
|
|
|
|
threads[i].set_indentation(indentation);
|
|
|
|
|
if !threaded.contains(&i) {
|
|
|
|
|
threaded.push(i);
|
|
|
|
|
}
|
|
|
|
|
let indentation =
|
|
|
|
|
if thread.has_message() {
|
|
|
|
|
threads[i].set_indentation(indentation);
|
|
|
|
|
if !threaded.contains(&i) {
|
|
|
|
|
threaded.push(i);
|
|
|
|
|
}
|
|
|
|
|
indentation + 1
|
|
|
|
|
} else if indentation > 0 {
|
|
|
|
|
indentation
|
|
|
|
|
} else {
|
|
|
|
|
indentation + 1
|
|
|
|
|
};
|
|
|
|
|
if thread.has_children() {
|
|
|
|
|
let mut fc = thread.get_first_child().unwrap();
|
|
|
|
|
loop {
|
|
|
|
|
build_threaded(threads, indentation, threaded, fc, i, collection);
|
|
|
|
|
let thread_ = threads[fc];
|
|
|
|
|
if !thread_.has_sibling() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
fc = thread_.get_next_sibling().unwrap();
|
|
|
|
|
indentation + 1
|
|
|
|
|
} else if indentation > 0 {
|
|
|
|
|
indentation
|
|
|
|
|
} else {
|
|
|
|
|
indentation + 1
|
|
|
|
|
};
|
|
|
|
|
if thread.has_children() {
|
|
|
|
|
let mut fc = thread.get_first_child().unwrap();
|
|
|
|
|
loop {
|
|
|
|
|
build_threaded(threads, indentation, threaded, fc, i, collection);
|
|
|
|
|
let thread_ = threads[fc];
|
|
|
|
|
if !thread_.has_sibling() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
fc = thread_.get_next_sibling().unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i in &root_set {
|
|
|
|
|
build_threaded(&mut threads, 0, &mut threaded_collection, *i, *i, collection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i in &root_set {
|
|
|
|
|
build_threaded(
|
|
|
|
|
&mut threads,
|
|
|
|
|
0,
|
|
|
|
|
&mut threaded_collection,
|
|
|
|
|
*i,
|
|
|
|
|
*i,
|
|
|
|
|
collection,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(threads, threaded_collection)
|
|
|
|
|
(threads, threaded_collection)
|
|
|
|
|
}
|
|
|
|
|