summaryrefslogtreecommitdiffstats
path: root/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/views')
-rw-r--r--src/views/mail.rs25
-rw-r--r--src/views/maillist.rs139
-rw-r--r--src/views/main.rs146
3 files changed, 118 insertions, 192 deletions
diff --git a/src/views/mail.rs b/src/views/mail.rs
index 93c781a..fe3a2f3 100644
--- a/src/views/mail.rs
+++ b/src/views/mail.rs
@@ -1,7 +1,8 @@
use std::path::PathBuf;
-use anyhow::Result;
-use anyhow::Error;
+use std::rc::Rc;
+use anyhow::Error;
+use anyhow::Result;
use cursive::Printer;
use cursive::Rect;
use cursive::View;
@@ -9,25 +10,27 @@ use cursive::XY;
use cursive::direction::Direction;
use cursive::event::Event;
use cursive::event::EventResult;
-use cursive::view::Nameable;
-use cursive::view::Selector;
use cursive::view::Scrollable;
-use cursive::views::NamedView;
-use cursive::views::TextView;
+use cursive::view::Selector;
+use cursive::view::ViewNotFound;
use cursive::views::LinearLayout;
use cursive::views::ScrollView;
-use result_inspect::ResultInspect;
+use cursive::views::TextView;
use mailparse::ParsedMail;
+use result_inspect::ResultInspect;
+
+use crate::runtime::Runtime;
pub struct MailView {
+ rt: Rc<Runtime>,
view: ScrollView<LinearLayout>,
}
impl MailView {
- pub fn create_for(database_path: PathBuf, id: String, mailfile: PathBuf, name: String) -> Result<NamedView<Self>> {
+ pub fn create_for(rt: Rc<Runtime>, id: String, mailfile: PathBuf) -> Result<Self> {
let query = format!("id:{}", id);
- let view = notmuch::Database::open(&database_path, notmuch::DatabaseMode::ReadOnly)?
+ let view = rt.database()
.create_query(&query)?
.search_messages()?
.map(|msg| {
@@ -58,7 +61,7 @@ impl MailView {
view
};
- Ok(MailView { view: view.scrollable() }.with_name(name))
+ Ok(MailView { rt, view: view.scrollable() })
}
fn parsed_mail_to_list_of_textviews<'a>(pm: &'a ParsedMail) -> Result<Vec<TextView>> {
@@ -103,7 +106,7 @@ impl View for MailView {
self.view.call_on_any(s, tpl);
}
- fn focus_view(&mut self, s: &Selector) -> Result<(), ()> {
+ fn focus_view(&mut self, s: &Selector) -> Result<(), ViewNotFound> {
self.view.focus_view(s)
}
diff --git a/src/views/maillist.rs b/src/views/maillist.rs
index dc13bf3..4f68790 100644
--- a/src/views/maillist.rs
+++ b/src/views/maillist.rs
@@ -1,45 +1,29 @@
use std::path::PathBuf;
-use std::ops::Deref;
+use std::rc::Rc;
-use anyhow::Result;
use anyhow::Context;
+use anyhow::Result;
+use chrono::naive::NaiveDateTime;
use cursive::Cursive;
-use cursive::Printer;
-use cursive::Rect;
-use cursive::View;
-use cursive::XY;
-use cursive::direction::Direction;
-use cursive::view::Nameable;
-use cursive::view::Selector;
-use cursive::event::Event;
-use cursive::event::EventResult;
-use cursive::views::NamedView;
+use cursive::view::SizeConstraint;
+use cursive::views::ResizedView;
use cursive_table_view::TableView;
use cursive_table_view::TableViewItem;
-use chrono::naive::NaiveDateTime;
+use getset::Getters;
use notmuch::Message;
use notmuch::MessageOwner;
-use getset::Getters;
-use cursive::views::ResizedView;
-use cursive::view::SizeConstraint;
-use crate::views::main::MainView;
use crate::views::mail::MailView;
+use crate::runtime::Runtime;
pub struct MaillistView {
+ rt: Rc<Runtime>,
view: ResizedView<TableView<MailListingData, MailListingColumn>>,
}
-impl Deref for MaillistView {
- type Target = TableView<MailListingData, MailListingColumn>;
- fn deref(&self) -> &Self::Target {
- self.view.get_inner()
- }
-}
-
impl MaillistView {
- pub fn create_for(database_path: PathBuf, query: &str, name: String) -> Result<NamedView<Self>> {
- debug!("Getting '{}' from '{}'", query, database_path.display());
+ pub fn for_query(rt: Rc<Runtime>, query: &str) -> Result<impl cursive::view::View> {
+ debug!("Getting '{}' from '{}'", query, rt.config().notmuch_database_path().display());
fn get_header_field_save<'o, O: MessageOwner + 'o>(msg: &Message<'o, O>, field: &str) -> String {
match msg.header(field) {
@@ -53,8 +37,7 @@ impl MaillistView {
}
}
- let items = notmuch::Database::open(&database_path, notmuch::DatabaseMode::ReadOnly)
- .context(format!("Opening database {}", database_path.display()))?
+ let items = rt.database()
.create_query(query)
.context("Creating the search query")?
.search_messages()
@@ -86,12 +69,11 @@ impl MaillistView {
})
})
.collect::<Result<Vec<_>>>()
- .context(format!("Creating MaillinglistView for '{}' on {}", query, database_path.display()))?;
+ .context(format!("Creating MaillinglistView for '{}' on {}", query, rt.config().notmuch_database_path().display()))?;
debug!("Found {} entries", items.len());
- let n = name.clone();
- let db_path = database_path.clone();
- let view = TableView::<MailListingData, MailListingColumn>::new()
+ let mailviewrt = rt.clone();
+ let view = TableView::<MailListingData,MailListingColumn>::new()
.column(MailListingColumn::Date, "Date", |c| c.width(20))
.column(MailListingColumn::Tags, "Tags", |c| c.width(20))
.column(MailListingColumn::From, "From", |c| c)
@@ -101,82 +83,61 @@ impl MaillistView {
.items(items)
.selected_item(0)
.on_submit(move |siv: &mut Cursive, row: usize, _: usize| {
- let (mail_id, filename) = siv.call_on_name(&n, move |table: &mut MaillistView| {
- table.view
- .get_inner_mut()
- .borrow_item(row)
- .map(|data| {
- debug!("Opening: {:?}", data);
- (data.mail_id.clone(), data.filename.clone())
+ let (mail_id, filename) = siv.call_on_name(crate::views::main::MAIN_VIEW_NAME, move |main: &mut crate::views::main::MainView| {
+ main.get_current_mux()
+ .map(|mux| {
+ if let Some(table) = mux.downcast_ref::<TableView<MailListingData, MailListingColumn>>() {
+ table
+ .borrow_item(row)
+ .map(|data| {
+ debug!("Opening: {:?}", data);
+ (data.mail_id.clone(), data.filename.clone())
+ })
+ } else {
+ unimplemented!()
+ }
})
})
.unwrap()
+ .unwrap()
.unwrap();
debug!("Showing mail {}", mail_id);
+ let mv = MailView::create_for(mailviewrt.clone(), mail_id, filename).unwrap();
- // Why do I have to do this? This is UGLY!
- let n = n.clone();
- let db_path = db_path.clone();
- let name = format!("{}-{}", n, mail_id);
- let mv = MailView::create_for(db_path, mail_id, filename, name).unwrap();
-
- siv.call_on_name(crate::views::main::MAIN_MUX_NAME, move |mux: &mut cursive_multiplex::Mux| {
- mux.add_right_of(mv, mux.root().build().unwrap());
+ siv.call_on_name(crate::views::main::MAIN_VIEW_NAME , move |main: &mut crate::views::main::MainView| {
+ main.get_current_tab_mut()
+ .map(|mux: &mut cursive_multiplex::Mux| {
+ mux.add_right_of(mv, mux.focus());
+ })
});
// use the mail ID to get the whole thread and open it as a table item
});
- Ok(MaillistView { view: ResizedView::new(SizeConstraint::Full, SizeConstraint::Full, view )}.with_name(name))
- }
-
- pub fn borrow_item(&mut self, idx: usize) -> Option<&MailListingData> {
- self.view.get_inner_mut().borrow_item(idx)
+ Ok({
+ MaillistView {
+ rt,
+ view: ResizedView::new(SizeConstraint::Full, SizeConstraint::Full, view)
+ }
+ })
}
}
-impl View for MaillistView {
- fn draw(&self, printer: &Printer) {
- self.view.draw(printer)
- }
-
- fn layout(&mut self, xy: XY<usize>) {
- self.view.layout(xy)
- }
-
- fn needs_relayout(&self) -> bool {
- self.view.needs_relayout()
- }
-
- fn required_size(&mut self, constraint: XY<usize>) -> XY<usize> {
- self.view.required_size(constraint)
- }
-
- fn on_event(&mut self, e: Event) -> EventResult {
- self.view.on_event(e)
- }
+impl cursive::view::ViewWrapper for MaillistView {
+ type V = ResizedView<TableView<MailListingData, MailListingColumn>>;
- fn call_on_any<'a>(&mut self, s: &Selector, tpl: &'a mut (dyn FnMut(&mut (dyn View + 'static)) + 'a)) {
- self.view.call_on_any(s, tpl);
- }
-
- fn focus_view(&mut self, s: &Selector) -> Result<(), ()> {
- self.view.focus_view(s)
- }
-
- fn take_focus(&mut self, source: Direction) -> bool {
- self.view.take_focus(source)
- }
-
- fn important_area(&self, view_size: XY<usize>) -> Rect {
- self.view.important_area(view_size)
+ fn with_view<F, R>(&self, f: F) -> Option<R>
+ where F: FnOnce(&Self::V) -> R
+ {
+ Some(f(&self.view))
}
- fn type_name(&self) -> &'static str {
- self.view.type_name()
+ fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
+ where F: FnOnce(&mut Self::V) -> R
+ {
+ Some(f(&mut self.view))
}
-
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
diff --git a/src/views/main.rs b/src/views/main.rs
index af9dcea..2cf54c3 100644
--- a/src/views/main.rs
+++ b/src/views/main.rs
@@ -1,48 +1,84 @@
+use std::rc::Rc;
+
use anyhow::Result;
-use cursive::Cursive;
use cursive::Printer;
use cursive::Rect;
use cursive::View;
use cursive::XY;
use cursive::direction::Direction;
-use cursive::event::Callback;
use cursive::event::Event;
use cursive::event::EventResult;
+use cursive::event::Key;
+use cursive::traits::Resizable;
use cursive::view::Nameable;
use cursive::view::Selector;
-use cursive::views::Dialog;
-use cursive::views::EditView;
+use cursive::view::SizeConstraint;
+use cursive::view::ViewNotFound;
use cursive::views::NamedView;
use cursive::views::ResizedView;
-use cursive::traits::Resizable;
-use cursive_multiplex::Mux;
-use cursive::view::SizeConstraint;
-use cursive::event::Key;
use getset::{Getters, MutGetters};
use crate::bindings::BindingCaller;
use crate::bindings::Bindings;
-use crate::configuration::Configuration;
-use crate::views::mail::MailView;
-use crate::views::maillist::MailListingData;
-use crate::views::maillist::MaillistView;
+use crate::tabs::*;
+use crate::runtime::Runtime;
pub const MAIN_VIEW_NAME: &'static str = "main_view";
-pub const MAIN_MUX_NAME: &'static str = "main_mux";
-pub const MAIN_MAIL_LIST_NAME: &'static str = "main_mail_list";
#[derive(Getters, MutGetters)]
pub struct MainView {
- config: Configuration,
- muxroot: cursive_multiplex::Id,
+ rt: Rc<Runtime>,
#[getset(get = "pub", get_mut = "pub")]
- tabs: cursive_tabs::TabPanel<String>,
+ tabs: crate::tabs::Tabs,
bindings: Bindings,
bindings_caller: Option<ResizedView<NamedView<BindingCaller>>>,
}
+impl MainView {
+ pub fn new(rt: Rc<Runtime>) -> Result<NamedView<Self>> {
+ let default_query = rt.config().notmuch_default_query();
+ let tabs = Tabs::new(default_query, rt.clone())?;
+ let bindings = crate::bindings::get_bindings();
+
+ Ok(MainView { rt, tabs, bindings, bindings_caller: None }.with_name(MAIN_VIEW_NAME))
+ }
+
+ pub fn get_current_tab(&self) -> Option<&cursive_multiplex::Mux> {
+ if let Some(mux) = self.tabs.get_active_tab() {
+ mux.downcast_ref::<cursive_multiplex::Mux>()
+ } else {
+ None
+ }
+ }
+
+ pub fn get_current_mux(&self) -> Option<&Box<dyn cursive::View>> {
+ if let Some(mux) = self.get_current_tab() {
+ return mux.get_current_view()
+ }
+
+ None
+ }
+
+ pub fn get_current_tab_mut(&mut self) -> Option<&mut cursive_multiplex::Mux> {
+ if let Some(mux) = self.tabs.get_active_tab_mut() {
+ mux.downcast_mut::<cursive_multiplex::Mux>()
+ } else {
+ None
+ }
+ }
+
+ pub fn get_current_mux_mut(&mut self) -> Option<&mut Box<dyn cursive::View>> {
+ if let Some(mut mux) = self.get_current_tab_mut() {
+ return mux.get_current_view_mut()
+ }
+
+ None
+ }
+
+}
+
impl View for MainView {
fn draw(&self, printer: &Printer) {
self.tabs.draw(printer);
@@ -99,7 +135,7 @@ impl View for MainView {
self.tabs.call_on_any(s, tpl);
}
- fn focus_view(&mut self, s: &Selector) -> Result<(), ()> {
+ fn focus_view(&mut self, s: &Selector) -> Result<(), ViewNotFound> {
self.tabs.focus_view(s)
}
@@ -116,77 +152,3 @@ impl View for MainView {
}
}
-
-impl MainView {
- pub fn new(config: Configuration) -> Result<NamedView<Self>> {
- let mut tab = cursive_multiplex::Mux::new();
- let muxroot = tab.root().build().unwrap();
-
- {
- let dbpath = config.notmuch_database_path();
- let dbquery = config.notmuch_default_query();
- let mlname = MAIN_MAIL_LIST_NAME.to_string();
- let view = MaillistView::create_for(dbpath.to_path_buf(), dbquery, mlname)?;
-
- let _ = tab.add_right_of(view, muxroot);
- }
-
- let tabs = cursive_tabs::TabPanel::default()
- .with_bar_alignment(cursive_tabs::Align::Start)
- .with_bar_placement(cursive_tabs::Placement::HorizontalTop)
- .with_tab(config.notmuch_default_query().clone(), tab.with_name(MAIN_MUX_NAME));
-
- let bindings = crate::bindings::get_bindings();
-
- Ok(MainView { config, muxroot, tabs, bindings, bindings_caller: None }.with_name(MAIN_VIEW_NAME))
- }
-
- pub fn add_tab<T: View>(&mut self, id: String, view: T) {
- self.tabs.add_tab(id, view)
- }
-
- pub fn config(&self) -> &Configuration {
- &self.config
- }
-
- pub fn add_notmuch_query_layer(siv: &mut Cursive) {
- use crate::util::dialog_for;
- use crate::util::error_dialog_for;
-
- let edit_view = EditView::new()
- .on_submit(move |siv: &mut Cursive, query: &str| {
- siv.call_on_name(MAIN_VIEW_NAME, move |main_view: &mut MainView| {
- main_view.config().notmuch_database_path().clone()
- })
- .map(|dbpath| {
- let t = MaillistView::create_for(dbpath.to_path_buf(), query, query.to_string())?
- .full_screen()
- .with_name(format!("{}-view", query));
-
- siv.call_on_name(MAIN_VIEW_NAME, move |main_view: &mut MainView| {
- main_view.add_tab(query.to_string(), t);
- });
-
- siv.pop_layer();
- Ok(())
- })
- .unwrap_or_else(|| {
- siv.pop_layer();
- siv.add_layer(dialog_for("Failed to get database connection set up"));
- Ok(())
- })
- .unwrap_or_else(|e: anyhow::Error| {
- siv.pop_layer();
- siv.add_layer(error_dialog_for(e))
- });
- })
- .with_name("query");
-
- siv.add_layer({
- Dialog::around(edit_view)
- .title("Query")
- .min_width(80)
- })
- }
-
-}