Retrieve directory entries in a thread

the UI is now more responsive for large directories
master
Jos van den Oever 2017-08-17 01:52:35 +02:00
parent 822319764f
commit ab2889ce1b
1 changed files with 62 additions and 37 deletions

View File

@ -7,12 +7,17 @@ use std::path::PathBuf;
use std::ffi::OsString;
use std::default::Default;
use std::thread;
use std::sync::{Arc, Mutex};
use std::marker::Sync;
use std::collections::HashMap;
pub struct DirEntry {
name: OsString,
metadata: Option<Metadata>,
}
type Incoming<T> = Arc<Mutex<HashMap<usize, Vec<T>>>>;
impl Item for DirEntry {
fn create(name: &str) -> DirEntry {
DirEntry {
@ -35,20 +40,28 @@ impl Item for DirEntry {
fn file_size(&self) -> u64 {
self.metadata.as_ref().map_or(0, |m|m.len())
}
fn retrieve(&self, parents: Vec<&DirEntry>) -> Vec<DirEntry> {
fn retrieve(id: usize, parents: Vec<&DirEntry>,
q: Incoming<Self>,
emit: TreeEmitter) {
let mut v = Vec::new();
let path: PathBuf = parents.into_iter().map(|e| &e.name).collect();
if let Ok(it) = read_dir(path) {
for i in it.filter_map(|v| v.ok()) {
let de = DirEntry {
name: i.file_name(),
metadata: i.metadata().ok()
};
v.push(de);
thread::spawn(move || {
if let Ok(it) = read_dir(path) {
for i in it.filter_map(|v| v.ok()) {
let de = DirEntry {
name: i.file_name(),
metadata: i.metadata().ok()
};
v.push(de);
}
}
}
v.sort_by(|a, b| a.name.cmp(&b.name));
v
v.sort_by(|a, b| a.name.cmp(&b.name));
let mut map = q.lock().unwrap();
if !map.contains_key(&id) {
map.insert(id, v);
emit.new_data_ready(0, 0);
}
});
}
}
@ -64,7 +77,7 @@ impl Default for DirEntry {
pub trait Item: Default {
fn create(name: &str) -> Self;
fn can_fetch_more(&self) -> bool;
fn retrieve(&self, parents: Vec<&Self>) -> Vec<Self>;
fn retrieve(id: usize, parents: Vec<&Self>, q: Incoming<Self>, emit: TreeEmitter);
fn file_name(&self) -> String;
fn file_permissions(&self) -> c_int;
fn file_type(&self) -> c_int;
@ -85,9 +98,10 @@ pub struct RGeneralItemModel<T: Item> {
model: TreeUniformTree,
entries: Vec<Entry<T>>,
path: String,
incoming: Incoming<T>,
}
impl<T: Item> RGeneralItemModel<T> {
impl<T: Item> RGeneralItemModel<T> where T: Sync + Send {
fn reset(&mut self) {
self.model.begin_reset_model();
self.entries.clear();
@ -130,32 +144,41 @@ impl<T: Item> RGeneralItemModel<T> {
}
fn retrieve(&mut self, row: c_int, parent: usize) {
let id = self.get_index(row, parent).unwrap();
let mut new_entries = Vec::new();
let mut children = Vec::new();
{
let parents = self.get_parents(id);
let entry = &self.entries[id];
let entries = entry.data.retrieve(parents);
for (r, d) in entries.into_iter().enumerate() {
let e = Entry {
parent: id,
row: r,
children: None,
data: d,
};
children.push(self.entries.len() + r);
new_entries.push(e);
let parents = self.get_parents(id);
let incoming = self.incoming.clone();
T::retrieve(id, parents, incoming, self.emit.clone());
}
fn process_incoming(&mut self) {
let mut incoming = self.incoming.lock().unwrap();
for (id, entries) in incoming.drain() {
if self.entries[id].children.is_some() {
continue;
}
let mut new_entries = Vec::new();
let mut children = Vec::new();
{
for (r, d) in entries.into_iter().enumerate() {
let e = Entry {
parent: id,
row: r,
children: None,
data: d,
};
children.push(self.entries.len() + r);
new_entries.push(e);
}
if new_entries.len() > 0 {
let ref e = self.entries[id];
self.model.begin_insert_rows(e.row as c_int, e.parent, 0,
(new_entries.len() - 1) as c_int);
}
}
self.entries[id].children = Some(children);
if new_entries.len() > 0 {
self.model.begin_insert_rows(row, parent, 0,
(new_entries.len() - 1) as c_int);
self.entries.append(&mut new_entries);
self.model.end_insert_rows();
}
}
self.entries[id].children = Some(children);
if new_entries.len() > 0 {
self.entries.append(&mut new_entries);
self.model.end_insert_rows();
}
}
fn get_parents(&self, id: usize) -> Vec<&T> {
let mut pos = id;
@ -168,13 +191,14 @@ impl<T: Item> RGeneralItemModel<T> {
}
}
impl<T: Item> TreeTrait for RGeneralItemModel<T> {
impl<T: Item> TreeTrait for RGeneralItemModel<T> where T: Sync + Send {
fn create(emit: TreeEmitter, model: TreeUniformTree) -> Self {
let mut tree = RGeneralItemModel {
emit: emit,
model: model,
entries: Vec::new(),
path: String::new()
path: String::new(),
incoming: Arc::new(Mutex::new(HashMap::new()))
};
tree.reset();
tree
@ -199,6 +223,7 @@ impl<T: Item> TreeTrait for RGeneralItemModel<T> {
.unwrap_or(false)
}
fn fetch_more(&mut self, row: c_int, parent: usize) {
self.process_incoming();
if !self.can_fetch_more(row, parent) {
return;
}