use gtk::prelude::*; use gtk::glib; use super::state::{View, ViewManager}; use std::sync::Arc; use std::sync::Mutex; use std::rc::Rc; use std::thread; use crate::index::Index; use crate::index::GenState; pub struct Generate { vm : Rc } impl View for Generate { fn name(&self) -> &str { "generate" } fn set_vm(&mut self, vm : Rc) { self.vm = vm } fn make_current(&self) -> Option { let target_dir = Arc::new(Mutex::new(String::new())); let index_file = Arc::new(Mutex::new(String::new())); let (index_tx, index_rx) = std::sync::mpsc::channel(); let load_next = Rc::new(Mutex::new(false)); let splash = gtk::Window::new(gtk::WindowType::Popup); splash.set_type_hint(gtk::gdk::WindowTypeHint::Splashscreen); splash.set_decorated(false); splash.set_position(gtk::WindowPosition::Center); splash.set_resizable(false); splash.set_size_request(600, 200); let main = gtk::Box::new(gtk::Orientation::Vertical, 10); main.set_widget_name("generate"); let title = gtk::Label::new(Some("Generate Index")); title.set_widget_name("title"); let step = gtk::Label::new(Some("Choose A Target Directory")); step.set_halign(gtk::Align::Start); let btn = gtk::Button::with_label("Choose"); btn.set_sensitive(false); let header = gtk::Box::new(gtk::Orientation::Horizontal, 0); let pick = gtk::FileChooserWidget::builder() .create_folders(false) .action(gtk::FileChooserAction::SelectFolder) .build(); header.pack_start(&step, true, true, 10); header.pack_start(&btn, false, false, 10); main.pack_start(&title, false, false, 0); main.pack_start(&header, false, false, 0); main.pack_start(&pick, true, true, 0); splash.add(&main); pick.connect_selection_changed(glib::clone!(@weak btn => move |pick| { if pick.file().is_some() || pick.current_name().is_some() { btn.set_sensitive(true); } else { btn.set_sensitive(false); } })); { let target_dir = Arc::clone(&target_dir); let index_file = Arc::clone(&index_file); let load_next = Rc::clone(&load_next); btn.connect_clicked(glib::clone!( @weak splash, @weak header, @weak step, @weak pick, @weak main => move |btn| { let td = { target_dir.lock().unwrap().clone() }; if td.is_empty() { let uri = pick.uri().unwrap(); let path = uri.as_str().trim_start_matches("file://"); let mut target_dir = target_dir.lock().unwrap(); *target_dir = path.to_string(); step.set_text("Create A Index File"); btn.set_label("Create"); pick.set_action(gtk::FileChooserAction::Save); } else { let mut path = pick.current_folder().unwrap().to_str().unwrap().to_string(); path += "/"; path += pick.current_name().unwrap().to_string().as_str(); *index_file.lock().unwrap() = path; main.remove(&header); main.remove(&pick); let progress = gtk::ProgressBar::builder() .ellipsize(gtk::pango::EllipsizeMode::Middle) .show_text(true) .text("Generating") .build(); progress.set_margin(20); main.pack_start(&progress, true, false, 0); let (tx, rx) = glib::MainContext::channel(glib::Priority::default()); { let target_dir = Arc::clone(&target_dir); let index_file = Arc::clone(&index_file); let index_tx = index_tx.clone(); thread::spawn(move || { let path = target_dir.lock().unwrap().to_string(); let idx = Index::generate(path.as_str(), |s, p| { let text = match s { GenState::Fetching => { "Fetching" } GenState::Parsing => { "Parsing" } GenState::Merging => { "Merging" } }; tx.send(Some((text, p))).ok(); }); tx.send(Some(("Saving", 100))).ok(); idx.save(index_file.lock().unwrap().to_string()); tx.send(None).ok(); index_tx.send(idx) }); } let load_next = Rc::clone(&load_next); rx.attach(None, glib::clone!( @weak splash, @weak progress, @weak main => @default-return glib::Continue(false), move |value| match value { Some((s, p)) => { progress.pulse(); progress.set_fraction(f64::from(p) / 100.0); progress.set_text(Some(s)); glib::Continue(true) } None => { splash.close(); *load_next.lock().unwrap() = true; glib::Continue(false) } })); main.show_all(); } })); } let vm = Rc::clone(&self.vm); splash.connect_hide(move |_| { if *load_next.lock().unwrap() { let idx = index_rx.recv().unwrap(); vm.set_index(idx); vm.set_current_view("search"); } else if vm.get_current_view() == "generate" { vm.set_current_view("welcome") } }); splash.show_all(); None } } impl Generate { pub fn new() -> Self { Self { vm : Rc::new(ViewManager::empty()) } } }