2017-08-03 12:27:32 -07:00
|
|
|
use interface::*;
|
2017-08-13 23:54:05 -07:00
|
|
|
use std::fs::*;
|
2017-08-04 10:08:38 -07:00
|
|
|
use std::fs::read_dir;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::ffi::OsString;
|
2017-08-04 13:26:53 -07:00
|
|
|
use std::default::Default;
|
2017-08-05 02:37:01 -07:00
|
|
|
use std::thread;
|
2017-08-16 16:52:35 -07:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use std::marker::Sync;
|
|
|
|
use std::collections::HashMap;
|
2017-08-03 02:18:52 -07:00
|
|
|
|
2017-08-04 13:26:53 -07:00
|
|
|
pub struct DirEntry {
|
2017-08-04 10:08:38 -07:00
|
|
|
name: OsString,
|
2017-08-15 15:32:33 -07:00
|
|
|
metadata: Option<Metadata>,
|
2017-08-29 11:37:51 -07:00
|
|
|
path: Option<PathBuf>,
|
2017-08-30 12:58:01 -07:00
|
|
|
icon: Vec<u8>,
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
|
|
|
|
2017-08-16 16:52:35 -07:00
|
|
|
type Incoming<T> = Arc<Mutex<HashMap<usize, Vec<T>>>>;
|
|
|
|
|
2017-08-13 15:26:49 -07:00
|
|
|
impl Item for DirEntry {
|
|
|
|
fn create(name: &str) -> DirEntry {
|
2017-08-13 23:54:05 -07:00
|
|
|
DirEntry {
|
|
|
|
name: OsString::from(name),
|
2017-08-15 15:32:33 -07:00
|
|
|
metadata: metadata(name).ok(),
|
2017-08-29 11:37:51 -07:00
|
|
|
path: None,
|
2017-08-30 12:58:01 -07:00
|
|
|
icon: Vec::new()
|
2017-08-13 23:54:05 -07:00
|
|
|
}
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
2017-08-15 15:32:33 -07:00
|
|
|
fn can_fetch_more(&self) -> bool {
|
2017-08-29 11:37:51 -07:00
|
|
|
self.metadata.as_ref().map_or(false, |m| m.is_dir())
|
2017-08-15 15:32:33 -07:00
|
|
|
}
|
2017-08-12 15:00:48 -07:00
|
|
|
fn file_name(&self) -> String {
|
|
|
|
self.name.to_string_lossy().to_string()
|
|
|
|
}
|
2017-08-18 15:53:13 -07:00
|
|
|
fn file_path(&self) -> Option<String> {
|
|
|
|
self.path.as_ref().map(|p| p.to_string_lossy().into())
|
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_permissions(&self) -> i32 {
|
2017-08-12 15:00:48 -07:00
|
|
|
42
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_type(&self) -> i32 {
|
2017-08-15 15:32:33 -07:00
|
|
|
0
|
2017-08-13 23:54:05 -07:00
|
|
|
}
|
2017-08-18 08:21:02 -07:00
|
|
|
fn file_size(&self) -> Option<u64> {
|
2017-08-29 11:37:51 -07:00
|
|
|
self.metadata.as_ref().map(|m| m.len())
|
2017-08-13 23:54:05 -07:00
|
|
|
}
|
2017-08-30 12:58:01 -07:00
|
|
|
fn icon(&self) -> &[u8] {
|
|
|
|
&self.icon
|
|
|
|
}
|
2017-08-31 10:20:25 -07:00
|
|
|
fn retrieve(id: usize, parents: Vec<&DirEntry>, q: Incoming<Self>, emit: FileSystemTreeEmitter) {
|
2017-08-04 13:26:53 -07:00
|
|
|
let mut v = Vec::new();
|
2017-08-15 15:32:33 -07:00
|
|
|
let path: PathBuf = parents.into_iter().map(|e| &e.name).collect();
|
2017-08-16 16:52:35 -07:00
|
|
|
thread::spawn(move || {
|
2017-08-18 15:53:13 -07:00
|
|
|
if let Ok(it) = read_dir(&path) {
|
2017-08-16 16:52:35 -07:00
|
|
|
for i in it.filter_map(|v| v.ok()) {
|
|
|
|
let de = DirEntry {
|
|
|
|
name: i.file_name(),
|
2017-08-18 15:53:13 -07:00
|
|
|
metadata: i.metadata().ok(),
|
2017-08-29 11:37:51 -07:00
|
|
|
path: Some(i.path()),
|
2017-08-30 12:58:01 -07:00
|
|
|
icon: Vec::new(),
|
2017-08-16 16:52:35 -07:00
|
|
|
};
|
|
|
|
v.push(de);
|
|
|
|
}
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
2017-08-16 16:52:35 -07:00
|
|
|
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);
|
2017-08-22 10:17:35 -07:00
|
|
|
emit.new_data_ready(Some(id));
|
2017-08-16 16:52:35 -07:00
|
|
|
}
|
|
|
|
});
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for DirEntry {
|
|
|
|
fn default() -> DirEntry {
|
2017-08-13 23:54:05 -07:00
|
|
|
DirEntry {
|
|
|
|
name: OsString::new(),
|
2017-08-15 15:32:33 -07:00
|
|
|
metadata: None,
|
2017-08-29 11:37:51 -07:00
|
|
|
path: None,
|
2017-08-30 12:58:01 -07:00
|
|
|
icon: Vec::new(),
|
2017-08-13 23:54:05 -07:00
|
|
|
}
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Item: Default {
|
2017-08-13 15:26:49 -07:00
|
|
|
fn create(name: &str) -> Self;
|
2017-08-15 15:32:33 -07:00
|
|
|
fn can_fetch_more(&self) -> bool;
|
2017-08-31 10:20:25 -07:00
|
|
|
fn retrieve(id: usize, parents: Vec<&Self>, q: Incoming<Self>, emit: FileSystemTreeEmitter);
|
2017-08-12 15:00:48 -07:00
|
|
|
fn file_name(&self) -> String;
|
2017-08-18 15:53:13 -07:00
|
|
|
fn file_path(&self) -> Option<String>;
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_permissions(&self) -> i32;
|
|
|
|
fn file_type(&self) -> i32;
|
2017-08-18 08:21:02 -07:00
|
|
|
fn file_size(&self) -> Option<u64>;
|
2017-08-30 12:58:01 -07:00
|
|
|
fn icon(&self) -> &[u8];
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
|
|
|
|
2017-08-31 10:20:25 -07:00
|
|
|
pub type FileSystemTree = RGeneralItemModel<DirEntry>;
|
2017-08-04 13:26:53 -07:00
|
|
|
|
|
|
|
struct Entry<T: Item> {
|
2017-08-22 10:17:35 -07:00
|
|
|
parent: Option<usize>,
|
2017-08-04 11:10:26 -07:00
|
|
|
row: usize,
|
2017-08-04 13:26:53 -07:00
|
|
|
children: Option<Vec<usize>>,
|
2017-08-08 11:33:46 -07:00
|
|
|
data: T,
|
2017-08-04 10:08:38 -07:00
|
|
|
}
|
|
|
|
|
2017-08-04 13:26:53 -07:00
|
|
|
pub struct RGeneralItemModel<T: Item> {
|
2017-08-31 10:20:25 -07:00
|
|
|
emit: FileSystemTreeEmitter,
|
2017-09-03 06:13:11 -07:00
|
|
|
model: FileSystemTreeTree,
|
2017-08-08 11:33:46 -07:00
|
|
|
entries: Vec<Entry<T>>,
|
2017-08-18 02:44:37 -07:00
|
|
|
path: Option<String>,
|
2017-08-16 16:52:35 -07:00
|
|
|
incoming: Incoming<T>,
|
2017-08-04 10:08:38 -07:00
|
|
|
}
|
|
|
|
|
2017-08-29 11:37:51 -07:00
|
|
|
impl<T: Item> RGeneralItemModel<T>
|
|
|
|
where
|
|
|
|
T: Sync + Send,
|
|
|
|
{
|
2017-08-13 15:26:49 -07:00
|
|
|
fn reset(&mut self) {
|
2017-08-14 13:19:39 -07:00
|
|
|
self.model.begin_reset_model();
|
2017-08-13 15:26:49 -07:00
|
|
|
self.entries.clear();
|
2017-08-18 02:44:37 -07:00
|
|
|
if let Some(ref path) = self.path {
|
|
|
|
let root = Entry {
|
2017-08-22 10:17:35 -07:00
|
|
|
parent: None,
|
2017-08-18 02:44:37 -07:00
|
|
|
row: 0,
|
|
|
|
children: None,
|
2017-09-01 14:14:47 -07:00
|
|
|
data: T::create(path),
|
2017-08-18 02:44:37 -07:00
|
|
|
};
|
|
|
|
self.entries.push(root);
|
|
|
|
}
|
2017-08-14 13:19:39 -07:00
|
|
|
self.model.end_reset_model();
|
2017-08-13 15:26:49 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn get(&self, item: usize) -> &Entry<T> {
|
|
|
|
&self.entries[item]
|
2017-08-04 10:08:38 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn retrieve(&mut self, item: usize) {
|
|
|
|
let parents = self.get_parents(item);
|
2017-08-16 16:52:35 -07:00
|
|
|
let incoming = self.incoming.clone();
|
2017-08-22 04:45:34 -07:00
|
|
|
T::retrieve(item, parents, incoming, self.emit.clone());
|
2017-08-16 16:52:35 -07:00
|
|
|
}
|
|
|
|
fn process_incoming(&mut self) {
|
2017-08-22 08:02:12 -07:00
|
|
|
if let Ok(ref mut incoming) = self.incoming.try_lock() {
|
|
|
|
for (id, entries) in incoming.drain() {
|
|
|
|
if self.entries[id].children.is_some() {
|
|
|
|
continue;
|
2017-08-16 16:52:35 -07:00
|
|
|
}
|
2017-08-22 08:02:12 -07:00
|
|
|
let mut new_entries = Vec::new();
|
|
|
|
let mut children = Vec::new();
|
|
|
|
{
|
|
|
|
for (r, d) in entries.into_iter().enumerate() {
|
|
|
|
let e = Entry {
|
2017-08-22 10:17:35 -07:00
|
|
|
parent: Some(id),
|
2017-08-22 08:02:12 -07:00
|
|
|
row: r,
|
|
|
|
children: None,
|
|
|
|
data: d,
|
|
|
|
};
|
|
|
|
children.push(self.entries.len() + r);
|
|
|
|
new_entries.push(e);
|
|
|
|
}
|
2017-09-01 14:14:47 -07:00
|
|
|
if !new_entries.is_empty() {
|
2017-08-29 11:37:51 -07:00
|
|
|
self.model.begin_insert_rows(
|
|
|
|
Some(id),
|
|
|
|
0,
|
|
|
|
(new_entries.len() - 1),
|
|
|
|
);
|
2017-08-22 08:02:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self.entries[id].children = Some(children);
|
2017-09-01 14:14:47 -07:00
|
|
|
if !new_entries.is_empty() {
|
2017-08-22 08:02:12 -07:00
|
|
|
self.entries.append(&mut new_entries);
|
|
|
|
self.model.end_insert_rows();
|
2017-08-16 16:52:35 -07:00
|
|
|
}
|
|
|
|
}
|
2017-08-04 10:08:38 -07:00
|
|
|
}
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
|
|
|
fn get_parents(&self, id: usize) -> Vec<&T> {
|
2017-08-22 10:17:35 -07:00
|
|
|
let mut pos = Some(id);
|
2017-08-04 13:26:53 -07:00
|
|
|
let mut e = Vec::new();
|
2017-08-22 10:17:35 -07:00
|
|
|
while let Some(p) = pos {
|
|
|
|
e.push(p);
|
|
|
|
pos = self.entries[p].parent;
|
2017-08-04 13:26:53 -07:00
|
|
|
}
|
|
|
|
e.into_iter().rev().map(|i| &self.entries[i].data).collect()
|
2017-08-04 10:08:38 -07:00
|
|
|
}
|
2017-08-03 12:27:32 -07:00
|
|
|
}
|
|
|
|
|
2017-08-31 10:20:25 -07:00
|
|
|
impl<T: Item> FileSystemTreeTrait for RGeneralItemModel<T>
|
2017-08-29 11:37:51 -07:00
|
|
|
where
|
|
|
|
T: Sync + Send,
|
|
|
|
{
|
2017-09-03 06:13:11 -07:00
|
|
|
fn create(emit: FileSystemTreeEmitter, model: FileSystemTreeTree) -> Self {
|
2017-08-13 15:26:49 -07:00
|
|
|
let mut tree = RGeneralItemModel {
|
2017-08-04 10:08:38 -07:00
|
|
|
emit: emit,
|
2017-08-13 15:26:49 -07:00
|
|
|
model: model,
|
|
|
|
entries: Vec::new(),
|
2017-08-18 02:44:37 -07:00
|
|
|
path: None,
|
2017-08-29 11:37:51 -07:00
|
|
|
incoming: Arc::new(Mutex::new(HashMap::new())),
|
2017-08-13 15:26:49 -07:00
|
|
|
};
|
|
|
|
tree.reset();
|
|
|
|
tree
|
2017-08-03 12:27:32 -07:00
|
|
|
}
|
2017-08-31 10:20:25 -07:00
|
|
|
fn emit(&self) -> &FileSystemTreeEmitter {
|
2017-08-05 02:37:01 -07:00
|
|
|
&self.emit
|
|
|
|
}
|
2017-08-31 00:01:14 -07:00
|
|
|
fn path(&self) -> Option<&str> {
|
2017-08-30 12:58:01 -07:00
|
|
|
self.path.as_ref().map(|s|&s[..])
|
2017-08-04 04:21:11 -07:00
|
|
|
}
|
2017-08-18 02:44:37 -07:00
|
|
|
fn set_path(&mut self, value: Option<String>) {
|
2017-08-13 15:26:49 -07:00
|
|
|
if self.path != value {
|
|
|
|
self.path = value;
|
|
|
|
self.emit.path_changed();
|
|
|
|
self.reset();
|
|
|
|
}
|
|
|
|
}
|
2017-08-22 10:17:35 -07:00
|
|
|
fn can_fetch_more(&self, item: Option<usize>) -> bool {
|
|
|
|
if let Some(item) = item {
|
|
|
|
let entry = self.get(item);
|
|
|
|
entry.children.is_none() && entry.data.can_fetch_more()
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
2017-08-13 15:26:49 -07:00
|
|
|
}
|
2017-08-22 10:17:35 -07:00
|
|
|
fn fetch_more(&mut self, item: Option<usize>) {
|
2017-08-16 16:52:35 -07:00
|
|
|
self.process_incoming();
|
2017-08-22 04:45:34 -07:00
|
|
|
if !self.can_fetch_more(item) {
|
2017-08-13 15:26:49 -07:00
|
|
|
return;
|
|
|
|
}
|
2017-08-22 10:17:35 -07:00
|
|
|
if let Some(item) = item {
|
|
|
|
self.retrieve(item);
|
2017-08-15 04:06:17 -07:00
|
|
|
}
|
2017-08-13 11:01:53 -07:00
|
|
|
}
|
2017-08-22 10:17:35 -07:00
|
|
|
fn row_count(&self, item: Option<usize>) -> usize {
|
2017-09-01 14:14:47 -07:00
|
|
|
if self.entries.is_empty() {
|
2017-08-22 10:17:35 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if let Some(i) = item {
|
|
|
|
let entry = self.get(i);
|
|
|
|
if let Some(ref children) = entry.children {
|
|
|
|
children.len()
|
|
|
|
} else {
|
|
|
|
// model does lazy loading, signal that data may be available
|
|
|
|
if self.can_fetch_more(item) {
|
|
|
|
self.emit.new_data_ready(item);
|
|
|
|
}
|
|
|
|
0
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
1
|
|
|
|
}
|
2017-08-04 04:21:11 -07:00
|
|
|
}
|
2017-08-22 10:17:35 -07:00
|
|
|
fn index(&self, item: Option<usize>, row: usize) -> usize {
|
|
|
|
if let Some(item) = item {
|
|
|
|
self.get(item).children.as_ref().unwrap()[row]
|
|
|
|
} else {
|
|
|
|
0
|
2017-08-04 10:08:38 -07:00
|
|
|
}
|
2017-08-22 10:17:35 -07:00
|
|
|
}
|
|
|
|
fn parent(&self, item: usize) -> Option<usize> {
|
|
|
|
self.entries[item].parent
|
|
|
|
}
|
|
|
|
fn row(&self, item: usize) -> usize {
|
|
|
|
self.entries[item].row
|
2017-08-04 04:21:11 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_name(&self, item: usize) -> String {
|
|
|
|
self.get(item).data.file_name()
|
2017-08-13 11:01:53 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_permissions(&self, item: usize) -> i32 {
|
|
|
|
self.get(item).data.file_permissions()
|
2017-08-13 11:01:53 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
#[allow(unused_variables)]
|
2017-08-30 12:58:01 -07:00
|
|
|
fn file_icon(&self, item: usize) -> &[u8] {
|
|
|
|
self.get(item).data.icon()
|
2017-08-12 15:00:48 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_path(&self, item: usize) -> Option<String> {
|
|
|
|
self.get(item).data.file_path()
|
2017-08-04 04:21:11 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_type(&self, item: usize) -> i32 {
|
|
|
|
self.get(item).data.file_type()
|
2017-08-13 23:54:05 -07:00
|
|
|
}
|
2017-08-22 04:45:34 -07:00
|
|
|
fn file_size(&self, item: usize) -> Option<u64> {
|
|
|
|
self.get(item).data.file_size()
|
2017-08-13 23:54:05 -07:00
|
|
|
}
|
2017-08-03 12:27:32 -07:00
|
|
|
}
|