use termion::event::Key;
use notify::{INotifyWatcher, Watcher, DebouncedEvent, RecursiveMode};
use std::io::Write;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::time::Duration;
use std::path::PathBuf;
use std::collections::HashMap;
use crate::files::{File, Files, ShortPaths};
use crate::listview::ListView;
use crate::miller_columns::MillerColumns;
use crate::widget::Widget;
use crate::tabview::{TabView, Tabbable};
use crate::preview::{Previewer, WillBeWidget};
use crate::fail::{HResult, HError, ErrorLog};
use crate::widget::{Events, WidgetCore};
use crate::proclist::ProcView;
use crate::bookmarks::BMPopup;
use crate::term::ScreenExt;
use crate::foldview::LogView;
#[derive(PartialEq)]
pub enum FileBrowserWidgets {
FileList(WillBeWidget<ListView<Files>>),
Previewer(Previewer),
}
impl Widget for FileBrowserWidgets {
fn get_core(&self) -> HResult<&WidgetCore> {
match self {
FileBrowserWidgets::FileList(widget) => widget.get_core(),
FileBrowserWidgets::Previewer(widget) => widget.get_core()
}
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
match self {
FileBrowserWidgets::FileList(widget) => widget.get_core_mut(),
FileBrowserWidgets::Previewer(widget) => widget.get_core_mut()
}
}
fn refresh(&mut self) -> HResult<()> {
match self {
FileBrowserWidgets::FileList(widget) => widget.refresh(),
FileBrowserWidgets::Previewer(widget) => widget.refresh()
}
}
fn get_drawlist(&self) -> HResult<String> {
match self {
FileBrowserWidgets::FileList(widget) => widget.get_drawlist(),
FileBrowserWidgets::Previewer(widget) => widget.get_drawlist()
}
}
}
pub struct FileBrowser {
pub columns: MillerColumns<FileBrowserWidgets>,
pub cwd: File,
pub prev_cwd: Option<File>,
selections: HashMap<File, File>,
cached_files: HashMap<File, Files>,
core: WidgetCore,
watcher: INotifyWatcher,
watches: Vec<PathBuf>,
dir_events: Arc<Mutex<Vec<DebouncedEvent>>>,
proc_view: Arc<Mutex<ProcView>>,
bookmarks: Arc<Mutex<BMPopup>>,
log_view: Arc<Mutex<LogView>>
}
impl Tabbable for TabView<FileBrowser> {
fn new_tab(&mut self) -> HResult<()> {
let mut tab = FileBrowser::new_cored(&self.active_tab_().core)?;
let proc_view = self.active_tab_().proc_view.clone();
let bookmarks = self.active_tab_().bookmarks.clone();
let log_view = self.active_tab_().log_view.clone();
tab.proc_view = proc_view;
tab.bookmarks = bookmarks;
tab.log_view = log_view;
self.push_widget(tab)?;
self.active += 1;
Ok(())
}
fn close_tab(&mut self) -> HResult<()> {
self.close_tab_()
}
fn next_tab(&mut self) -> HResult<()> {
self.next_tab_();
Ok(())
}
fn goto_tab(&mut self, index: usize) -> HResult<()> {
self.goto_tab_(index)
}
fn get_tab_names(&self) -> Vec<Option<String>> {
self.widgets.iter().map(|filebrowser| {
let path = filebrowser.cwd.path();
let last_dir = path.components().last().unwrap();
let dir_name = last_dir.as_os_str().to_string_lossy().to_string();
Some(dir_name)
}).collect()
}
fn active_tab(& self) -> & dyn Widget {
self.active_tab_()
}
fn active_tab_mut(&mut self) -> &mut dyn Widget {
self.active_tab_mut_()
}
fn on_tab_switch(&mut self) -> HResult<()> {
self.active_tab_mut().refresh()
}
fn on_key_sub(&mut self, key: Key) -> HResult<()> {
match key {
Key::Char('!') => {
let tab_dirs = self.widgets.iter().map(|w| w.cwd.clone())
.collect::<Vec<_>>();
let selected_files = self.widgets.iter().fold(HashMap::new(),
|mut f, w| {
let dir = w.cwd().unwrap().clone();
let selected_files = w.selected_files().unwrap();
f.insert(dir, selected_files);
f
});
self.widgets[self.active].exec_cmd(tab_dirs, selected_files)
}
_ => { self.active_tab_mut().on_key(key) }
}