From c2d40fe56e4f2546c781d366ce4198cba27a166e Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Fri, 9 Oct 2020 12:22:02 +0200 Subject: [PATCH] Move database access to background thread --- src/backend.rs | 349 +++++++++++++++++++++++++++++ src/dialogs/ensemble_editor.rs | 27 ++- src/dialogs/instrument_editor.rs | 27 ++- src/dialogs/instrument_selector.rs | 72 +++--- src/dialogs/part_editor.rs | 11 +- src/dialogs/person_editor.rs | 27 ++- src/dialogs/person_selector.rs | 71 +++--- src/dialogs/work_editor.rs | 35 +-- src/main.rs | 1 + src/window.rs | 70 +++--- 10 files changed, 542 insertions(+), 148 deletions(-) create mode 100644 src/backend.rs diff --git a/src/backend.rs b/src/backend.rs new file mode 100644 index 0000000..2b14230 --- /dev/null +++ b/src/backend.rs @@ -0,0 +1,349 @@ +use super::database::*; +use glib::Sender; + +enum BackendAction { + UpdatePerson(Person, Sender>), + GetPerson(i64, Sender>), + DeletePerson(i64, Sender>), + GetPersons(Sender>), + UpdateInstrument(Instrument, Sender>), + GetInstrument(i64, Sender>), + DeleteInstrument(i64, Sender>), + GetInstruments(Sender>), + UpdateWork(WorkInsertion, Sender>), + GetWorkDescriptions(i64, Sender>), + UpdateEnsemble(Ensemble, Sender>), + GetEnsemble(i64, Sender>), + DeleteEnsemble(i64, Sender>), + GetEnsembles(Sender>), +} + +use BackendAction::*; + +pub struct Backend { + action_sender: std::sync::mpsc::Sender, +} + +impl Backend { + pub fn new(url: &str) -> Self { + let url = url.to_string(); + + let (action_sender, action_receiver) = std::sync::mpsc::channel::(); + + std::thread::spawn(move || { + let db = Database::new(&url); + + for action in action_receiver { + match action { + UpdatePerson(person, sender) => { + db.update_person(person); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetPerson(id, sender) => { + let person = db.get_person(id); + sender + .send(person) + .expect("Failed to send result from database thread!"); + } + DeletePerson(id, sender) => { + db.delete_person(id); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetPersons(sender) => { + let persons = db.get_persons(); + sender + .send(persons) + .expect("Failed to send result from database thread!"); + } + UpdateInstrument(instrument, sender) => { + db.update_instrument(instrument); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetInstrument(id, sender) => { + let instrument = db.get_instrument(id); + sender + .send(instrument) + .expect("Failed to send result from database thread!"); + } + DeleteInstrument(id, sender) => { + db.delete_instrument(id); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetInstruments(sender) => { + let instruments = db.get_instruments(); + sender + .send(instruments) + .expect("Failed to send result from database thread!"); + } + UpdateWork(work, sender) => { + db.update_work(work); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetWorkDescriptions(id, sender) => { + let works = db.get_work_descriptions(id); + sender + .send(works) + .expect("Failed to send result from database thread!"); + } + UpdateEnsemble(ensemble, sender) => { + db.update_ensemble(ensemble); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetEnsemble(id, sender) => { + let ensemble = db.get_ensemble(id); + sender + .send(ensemble) + .expect("Failed to send result from database thread!"); + } + DeleteEnsemble(id, sender) => { + db.delete_ensemble(id); + sender + .send(Ok(())) + .expect("Failed to send result from database thread!"); + } + GetEnsembles(sender) => { + let ensembles = db.get_ensembles(); + sender + .send(ensembles) + .expect("Failed to send result from database thread!"); + } + } + } + }); + + Backend { + action_sender: action_sender, + } + } + + pub fn update_person) -> () + 'static>( + &self, + person: Person, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(UpdatePerson(person, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_person) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetPerson(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn delete_person) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(DeletePerson(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_persons) -> () + 'static>(&self, callback: F) { + let (sender, receiver) = glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetPersons(sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn update_instrument) -> () + 'static>( + &self, + instrument: Instrument, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(UpdateInstrument(instrument, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_instrument) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetInstrument(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn delete_instrument) -> () + 'static>( + &self, + id: i64, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(DeleteInstrument(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_instruments) -> () + 'static>(&self, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetInstruments(sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn update_work) -> () + 'static>( + &self, + work: WorkInsertion, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(UpdateWork(work, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_work_descriptions) -> () + 'static>( + &self, + id: i64, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetWorkDescriptions(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn update_ensemble) -> () + 'static>( + &self, + ensemble: Ensemble, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(UpdateEnsemble(ensemble, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_ensemble) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetEnsemble(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn delete_ensemble) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(DeleteEnsemble(id, sender)) + .expect("Failed to send action to database thread!"); + } + + pub fn get_ensembles) -> () + 'static>(&self, callback: F) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetEnsembles(sender)) + .expect("Failed to send action to database thread!"); + } +} diff --git a/src/dialogs/ensemble_editor.rs b/src/dialogs/ensemble_editor.rs index c17c48f..aef8f43 100644 --- a/src/dialogs/ensemble_editor.rs +++ b/src/dialogs/ensemble_editor.rs @@ -1,18 +1,26 @@ +use crate::backend::*; use crate::database::*; use glib::clone; use gtk::prelude::*; use gtk_macros::get_widget; use std::rc::Rc; -pub struct EnsembleEditor { +pub struct EnsembleEditor +where + F: Fn(Ensemble) -> () + 'static, +{ window: gtk::Window, + callback: F, id: i64, name_entry: gtk::Entry, } -impl EnsembleEditor { - pub fn new () + 'static, P: IsA>( - db: Rc, +impl EnsembleEditor +where + F: Fn(Ensemble) -> () + 'static, +{ + pub fn new>( + backend: Rc, parent: &P, ensemble: Option, callback: F, @@ -34,8 +42,9 @@ impl EnsembleEditor { }; let result = Rc::new(EnsembleEditor { - id: id, window: window, + callback: callback, + id: id, name_entry: name_entry, }); @@ -44,15 +53,15 @@ impl EnsembleEditor { })); save_button.connect_clicked(clone!(@strong result => move |_| { - result.window.close(); - let ensemble = Ensemble { id: result.id, name: result.name_entry.get_text().to_string(), }; - db.update_ensemble(ensemble.clone()); - callback(ensemble); + backend.update_ensemble(ensemble.clone(), clone!(@strong result => move |_| { + result.window.close(); + (result.callback)(ensemble.clone()); + })); })); result.window.set_transient_for(Some(parent)); diff --git a/src/dialogs/instrument_editor.rs b/src/dialogs/instrument_editor.rs index b9e454b..1174351 100644 --- a/src/dialogs/instrument_editor.rs +++ b/src/dialogs/instrument_editor.rs @@ -1,18 +1,26 @@ +use crate::backend::*; use crate::database::*; use glib::clone; use gtk::prelude::*; use gtk_macros::get_widget; use std::rc::Rc; -pub struct InstrumentEditor { +pub struct InstrumentEditor +where + F: Fn(Instrument) -> () + 'static, +{ window: gtk::Window, + callback: F, id: i64, name_entry: gtk::Entry, } -impl InstrumentEditor { - pub fn new () + 'static, P: IsA>( - db: Rc, +impl InstrumentEditor +where + F: Fn(Instrument) -> () + 'static, +{ + pub fn new>( + backend: Rc, parent: &P, instrument: Option, callback: F, @@ -34,8 +42,9 @@ impl InstrumentEditor { }; let result = Rc::new(InstrumentEditor { - id: id, window: window, + callback: callback, + id: id, name_entry: name_entry, }); @@ -44,15 +53,15 @@ impl InstrumentEditor { })); save_button.connect_clicked(clone!(@strong result => move |_| { - result.window.close(); - let instrument = Instrument { id: result.id, name: result.name_entry.get_text().to_string(), }; - db.update_instrument(instrument.clone()); - callback(instrument); + backend.update_instrument(instrument.clone(), clone!(@strong result => move |_| { + result.window.close(); + (result.callback)(instrument.clone()); + })); })); result.window.set_transient_for(Some(parent)); diff --git a/src/dialogs/instrument_selector.rs b/src/dialogs/instrument_selector.rs index 5023bb1..a94109a 100644 --- a/src/dialogs/instrument_selector.rs +++ b/src/dialogs/instrument_selector.rs @@ -1,11 +1,11 @@ use super::selector_row::SelectorRow; use super::InstrumentEditor; +use crate::backend::Backend; use crate::database::*; use gio::prelude::*; use glib::clone; use gtk::prelude::*; use gtk_macros::get_widget; -use std::cell::RefCell; use std::convert::TryInto; use std::rc::Rc; @@ -13,10 +13,9 @@ pub struct InstrumentSelector where F: Fn(Instrument) -> () + 'static, { - db: Rc, + backend: Rc, window: gtk::Window, callback: F, - instruments: RefCell>, list: gtk::ListBox, search_entry: gtk::SearchEntry, } @@ -25,7 +24,7 @@ impl InstrumentSelector where F: Fn(Instrument) -> () + 'static, { - pub fn new>(db: Rc, parent: &P, callback: F) -> Rc { + pub fn new>(backend: Rc, parent: &P, callback: F) -> Rc { let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/instrument_selector.ui"); @@ -34,47 +33,48 @@ where get_widget!(builder, gtk::SearchEntry, search_entry); get_widget!(builder, gtk::ListBox, list); - let instruments = db.get_instruments(); - - for (index, instrument) in instruments.iter().enumerate() { - let label = gtk::Label::new(Some(&instrument.name)); - label.set_halign(gtk::Align::Start); - let row = SelectorRow::new(index.try_into().unwrap(), &label); - row.show_all(); - list.insert(&row, -1); - } - let result = Rc::new(InstrumentSelector { - db: db, + backend: backend, window: window, callback: callback, - instruments: RefCell::new(instruments), search_entry: search_entry, list: list, }); result - .list - .connect_row_activated(clone!(@strong result => move |_, row| { - result.window.close(); - let row = row.get_child().unwrap().downcast::().unwrap(); - let index: usize = row.get_index().try_into().unwrap(); - (result.callback)(result.instruments.borrow()[index].clone()); + .backend + .get_instruments(clone!(@strong result => move |instruments| { + for (index, instrument) in instruments.iter().enumerate() { + let label = gtk::Label::new(Some(&instrument.name)); + label.set_halign(gtk::Align::Start); + let row = SelectorRow::new(index.try_into().unwrap(), &label); + row.show_all(); + result.list.insert(&row, -1); + } + + result + .list + .connect_row_activated(clone!(@strong result, @strong instruments => move |_, row| { + result.window.close(); + let row = row.get_child().unwrap().downcast::().unwrap(); + let index: usize = row.get_index().try_into().unwrap(); + (result.callback)(instruments[index].clone()); + })); + + result + .list + .set_filter_func(Some(Box::new(clone!(@strong result => move |row| { + let row = row.get_child().unwrap().downcast::().unwrap(); + let index: usize = row.get_index().try_into().unwrap(); + let search = result.search_entry.get_text().to_string(); + + search.is_empty() || instruments[index] + .name + .to_lowercase() + .contains(&result.search_entry.get_text().to_string().to_lowercase()) + })))); })); - result - .list - .set_filter_func(Some(Box::new(clone!(@strong result => move |row| { - let row = row.get_child().unwrap().downcast::().unwrap(); - let index: usize = row.get_index().try_into().unwrap(); - let search = result.search_entry.get_text().to_string(); - - search.is_empty() || result.instruments.borrow()[index] - .name - .to_lowercase() - .contains(&result.search_entry.get_text().to_string().to_lowercase()) - })))); - result .search_entry .connect_search_changed(clone!(@strong result => move |_| { @@ -83,7 +83,7 @@ where add_button.connect_clicked(clone!(@strong result => move |_| { let editor = InstrumentEditor::new( - result.db.clone(), + result.backend.clone(), &result.window, None, clone!(@strong result => move |instrument| { diff --git a/src/dialogs/part_editor.rs b/src/dialogs/part_editor.rs index a0b0c0a..350d456 100644 --- a/src/dialogs/part_editor.rs +++ b/src/dialogs/part_editor.rs @@ -1,5 +1,6 @@ use super::selector_row::SelectorRow; use super::{InstrumentSelector, PersonSelector}; +use crate::backend::*; use crate::database::*; use glib::clone; use gtk::prelude::*; @@ -9,7 +10,7 @@ use std::convert::TryInto; use std::rc::Rc; pub struct PartEditor { - db: Rc, + backend: Rc, window: gtk::Window, title_entry: gtk::Entry, composer: RefCell>, @@ -20,7 +21,7 @@ pub struct PartEditor { impl PartEditor { pub fn new () + 'static, P: IsA>( - db: Rc, + backend: Rc, parent: &P, part: Option, callback: F, @@ -63,7 +64,7 @@ impl PartEditor { }); let result = Rc::new(PartEditor { - db: db, + backend: backend, window: window, title_entry: title_entry, composer: composer, @@ -86,7 +87,7 @@ impl PartEditor { })); composer_button.connect_clicked(clone!(@strong result => move |_| { - PersonSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |person| { + PersonSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |person| { result.composer.replace(Some(person.clone())); result.composer_label.set_text(&person.name_fl()); })).show(); @@ -98,7 +99,7 @@ impl PartEditor { })); add_instrument_button.connect_clicked(clone!(@strong result => move |_| { - InstrumentSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |instrument| { + InstrumentSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |instrument| { { let mut instruments = result.instruments.borrow_mut(); instruments.push(instrument); diff --git a/src/dialogs/person_editor.rs b/src/dialogs/person_editor.rs index c48bd08..f47cb7a 100644 --- a/src/dialogs/person_editor.rs +++ b/src/dialogs/person_editor.rs @@ -1,19 +1,27 @@ +use crate::backend::Backend; use crate::database::*; use glib::clone; use gtk::prelude::*; use gtk_macros::get_widget; use std::rc::Rc; -pub struct PersonEditor { +pub struct PersonEditor +where + F: Fn(Person) -> () + 'static, +{ window: gtk::Window, + callback: F, id: i64, first_name_entry: gtk::Entry, last_name_entry: gtk::Entry, } -impl PersonEditor { - pub fn new () + 'static, P: IsA>( - db: Rc, +impl PersonEditor +where + F: Fn(Person) -> () + 'static, +{ + pub fn new>( + backend: Rc, parent: &P, person: Option, callback: F, @@ -36,8 +44,9 @@ impl PersonEditor { }; let result = Rc::new(PersonEditor { - id: id, window: window, + callback: callback, + id: id, first_name_entry: first_name_entry, last_name_entry: last_name_entry, }); @@ -47,16 +56,16 @@ impl PersonEditor { })); save_button.connect_clicked(clone!(@strong result => move |_| { - result.window.close(); - let person = Person { id: result.id, first_name: result.first_name_entry.get_text().to_string(), last_name: result.last_name_entry.get_text().to_string(), }; - db.update_person(person.clone()); - callback(person); + backend.update_person(person.clone(), clone!(@strong result => move |_| { + result.window.close(); + (result.callback)(person.clone()); + })); })); result.window.set_transient_for(Some(parent)); diff --git a/src/dialogs/person_selector.rs b/src/dialogs/person_selector.rs index 234fb36..c095139 100644 --- a/src/dialogs/person_selector.rs +++ b/src/dialogs/person_selector.rs @@ -1,11 +1,11 @@ use super::selector_row::SelectorRow; use super::PersonEditor; +use crate::backend::Backend; use crate::database::*; use gio::prelude::*; use glib::clone; use gtk::prelude::*; use gtk_macros::get_widget; -use std::cell::RefCell; use std::convert::TryInto; use std::rc::Rc; @@ -13,10 +13,9 @@ pub struct PersonSelector where F: Fn(Person) -> () + 'static, { - db: Rc, + backend: Rc, window: gtk::Window, callback: F, - persons: RefCell>, list: gtk::ListBox, search_entry: gtk::SearchEntry, } @@ -25,7 +24,7 @@ impl PersonSelector where F: Fn(Person) -> () + 'static, { - pub fn new>(db: Rc, parent: &P, callback: F) -> Rc { + pub fn new>(backend: Rc, parent: &P, callback: F) -> Rc { let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/person_selector.ui"); @@ -34,47 +33,47 @@ where get_widget!(builder, gtk::SearchEntry, search_entry); get_widget!(builder, gtk::ListBox, list); - let persons = db.get_persons(); - - for (index, person) in persons.iter().enumerate() { - let label = gtk::Label::new(Some(&person.name_lf())); - label.set_halign(gtk::Align::Start); - let row = SelectorRow::new(index.try_into().unwrap(), &label); - row.show_all(); - list.insert(&row, -1); - } - let result = Rc::new(PersonSelector { - db: db, + backend: backend, window: window, callback: callback, - persons: RefCell::new(persons), search_entry: search_entry, list: list, }); result - .list - .connect_row_activated(clone!(@strong result => move |_, row| { - result.window.close(); - let row = row.get_child().unwrap().downcast::().unwrap(); - let index: usize = row.get_index().try_into().unwrap(); - (result.callback)(result.persons.borrow()[index].clone()); + .backend + .get_persons(clone!(@strong result => move |persons| { + for (index, person) in persons.iter().enumerate() { + let label = gtk::Label::new(Some(&person.name_lf())); + label.set_halign(gtk::Align::Start); + let row = SelectorRow::new(index.try_into().unwrap(), &label); + row.show_all(); + result.list.insert(&row, -1); + } + + result + .list + .connect_row_activated(clone!(@strong result, @strong persons => move |_, row| { + result.window.close(); + let row = row.get_child().unwrap().downcast::().unwrap(); + let index: usize = row.get_index().try_into().unwrap(); + (result.callback)(persons[index].clone()); + })); + + result + .list + .set_filter_func(Some(Box::new(clone!(@strong result => move |row| { + let row = row.get_child().unwrap().downcast::().unwrap(); + let index: usize = row.get_index().try_into().unwrap(); + let search = result.search_entry.get_text().to_string().to_lowercase(); + search.is_empty() || persons[index] + .name_lf() + .to_lowercase() + .contains(&search) + })))); })); - result - .list - .set_filter_func(Some(Box::new(clone!(@strong result => move |row| { - let row = row.get_child().unwrap().downcast::().unwrap(); - let index: usize = row.get_index().try_into().unwrap(); - let search = result.search_entry.get_text().to_string().to_lowercase(); - - search.is_empty() || result.persons.borrow()[index] - .name_lf() - .to_lowercase() - .contains(&search) - })))); - result .search_entry .connect_search_changed(clone!(@strong result => move |_| { @@ -83,7 +82,7 @@ where add_button.connect_clicked(clone!(@strong result => move |_| { let editor = PersonEditor::new( - result.db.clone(), + result.backend.clone(), &result.window, None, clone!(@strong result => move |person| { diff --git a/src/dialogs/work_editor.rs b/src/dialogs/work_editor.rs index da13924..a42253c 100644 --- a/src/dialogs/work_editor.rs +++ b/src/dialogs/work_editor.rs @@ -1,5 +1,6 @@ use super::selector_row::SelectorRow; use super::{InstrumentSelector, PersonSelector, PartEditor, SectionEditor}; +use crate::backend::*; use crate::database::*; use glib::clone; use gtk::prelude::*; @@ -49,9 +50,12 @@ impl PartOrSection { } } -pub struct WorkEditor { - db: Rc, +pub struct WorkEditor +where + F: Fn(WorkDescription) -> () + 'static, { + backend: Rc, window: gtk::Window, + callback: F, save_button: gtk::Button, id: i64, title_entry: gtk::Entry, @@ -63,9 +67,11 @@ pub struct WorkEditor { part_list: gtk::ListBox, } -impl WorkEditor { - pub fn new () + 'static, P: IsA>( - db: Rc, +impl WorkEditor +where + F: Fn(WorkDescription) -> () + 'static, { + pub fn new>( + backend: Rc, parent: &P, work: Option, callback: F, @@ -134,8 +140,9 @@ impl WorkEditor { }); let result = Rc::new(WorkEditor { - db: db, + backend: backend, window: window, + callback: callback, save_button: save_button, id: id, title_entry: title_entry, @@ -152,8 +159,6 @@ impl WorkEditor { })); result.save_button.connect_clicked(clone!(@strong result => move |_| { - result.window.close(); - let mut section_count: i64 = 0; let mut parts: Vec = Vec::new(); let mut sections: Vec = Vec::new(); @@ -179,12 +184,14 @@ impl WorkEditor { sections: sections, }; - result.db.update_work(work.clone().into()); - callback(work); + result.backend.update_work(work.clone().into(), clone!(@strong result => move |_| { + result.window.close(); + (result.callback)(work.clone()); + })); })); composer_button.connect_clicked(clone!(@strong result => move |_| { - PersonSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |person| { + PersonSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |person| { result.composer.replace(Some(person.clone())); result.composer_label.set_text(&person.name_fl()); result.save_button.set_sensitive(true); @@ -192,7 +199,7 @@ impl WorkEditor { })); add_instrument_button.connect_clicked(clone!(@strong result => move |_| { - InstrumentSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |instrument| { + InstrumentSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |instrument| { { let mut instruments = result.instruments.borrow_mut(); instruments.push(instrument); @@ -216,7 +223,7 @@ impl WorkEditor { })); add_part_button.connect_clicked(clone!(@strong result => move |_| { - PartEditor::new(result.db.clone(), &result.window, None, clone!(@strong result => move |part| { + PartEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |part| { { let mut structure = result.structure.borrow_mut(); structure.push(PartOrSection::part(part)); @@ -247,7 +254,7 @@ impl WorkEditor { if pos.is_part() { let editor = - PartEditor::new(result.db.clone(), &result.window, Some(pos.unwrap_part()), clone!(@strong result => move |part| { + PartEditor::new(result.backend.clone(), &result.window, Some(pos.unwrap_part()), clone!(@strong result => move |part| { result.structure.borrow_mut()[index] = PartOrSection::part(part); result.show_parts(); })); diff --git a/src/main.rs b/src/main.rs index 9684259..c0d2711 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use glib::clone; use std::cell::RefCell; use std::rc::Rc; +mod backend; mod database; mod dialogs; diff --git a/src/window.rs b/src/window.rs index 91b07e4..b993a36 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,3 +1,4 @@ +use super::backend::Backend; use super::database::*; use super::dialogs::*; use gio::prelude::*; @@ -12,7 +13,7 @@ use std::rc::Rc; pub struct Window { window: libhandy::ApplicationWindow, - db: Rc, + backend: Rc, leaflet: libhandy::Leaflet, persons: RefCell>, works: RefCell>, @@ -46,14 +47,13 @@ impl Window { get_widget!(builder, gtk::Box, recording_box); get_widget!(builder, gtk::ListBox, recording_list); - let db = Rc::new(Database::new("test.sqlite")); - let persons = db.get_persons(); + let backend = Backend::new("test.sqlite"); let result = Rc::new(Window { window: window, - db: db, + backend: Rc::new(backend), leaflet: leaflet, - persons: RefCell::new(persons), + persons: RefCell::new(Vec::new()), works: RefCell::new(Vec::new()), recordings: RefCell::new(Vec::new()), sidebar_box: sidebar_box, @@ -108,9 +108,11 @@ impl Window { result.window, "add-person", clone!(@strong result => move |_, _| { - PersonEditor::new(result.db.clone(), &result.window, None, clone!(@strong result => move |_| { - result.persons.replace(result.db.get_persons()); - result.show_persons(); + PersonEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| { + result.backend.get_persons(clone!(@strong result => move |persons| { + result.persons.replace(persons); + result.show_persons(); + })); })).show(); }) ); @@ -119,7 +121,7 @@ impl Window { result.window, "add-instrument", clone!(@strong result => move |_, _| { - InstrumentEditor::new(result.db.clone(), &result.window, None, |instrument| { + InstrumentEditor::new(result.backend.clone(), &result.window, None, |instrument| { println!("{:?}", instrument); }).show(); }) @@ -129,9 +131,11 @@ impl Window { result.window, "add-work", clone!(@strong result => move |_, _| { - WorkEditor::new(result.db.clone(), &result.window, None, clone!(@strong result => move |_| { - result.persons.replace(result.db.get_persons()); - result.show_persons(); + WorkEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| { + result.backend.get_persons(clone!(@strong result => move |persons| { + result.persons.replace(persons); + result.show_persons(); + })); })).show(); }) ); @@ -140,7 +144,7 @@ impl Window { result.window, "add-ensemble", clone!(@strong result => move |_, _| { - EnsembleEditor::new(result.db.clone(), &result.window, None, |ensemble| { + EnsembleEditor::new(result.backend.clone(), &result.window, None, |ensemble| { println!("{:?}", ensemble); }).show(); }) @@ -155,12 +159,15 @@ impl Window { "edit-person", Some(glib::VariantTy::new("x").unwrap()), clone!(@strong result => move |_, id| { - let person = result.db.get_person(id.unwrap().get().unwrap()).unwrap(); - PersonEditor::new(result.db.clone(), &result.window, Some(person), clone!(@strong result => move |person| { - result.persons.replace(result.db.get_persons()); - result.show_persons(); - result.show_person(person); - })).show(); + result.backend.get_person(id.unwrap().get().unwrap(), clone!(@strong result => move |person| { + let person = person.unwrap(); + PersonEditor::new(result.backend.clone(), &result.window, Some(person), clone!(@strong result => move |person| { + result.backend.get_persons(clone!(@strong result => move |persons| { + result.persons.replace(persons); + result.show_persons(); + })); + })).show(); + })); }) ); @@ -169,10 +176,13 @@ impl Window { "delete-person", Some(glib::VariantTy::new("x").unwrap()), clone!(@strong result => move |_, id| { - result.db.delete_person(id.unwrap().get().unwrap()); - result.back(); - result.persons.replace(result.db.get_persons()); - result.show_persons(); + result.backend.delete_person(id.unwrap().get().unwrap(), clone!(@strong result => move |_| { + result.back(); + result.backend.get_persons(clone!(@strong result => move |persons| { + result.persons.replace(persons); + result.show_persons(); + })); + })); }) ); @@ -218,13 +228,13 @@ impl Window { self.header_menu_button.set_menu_model(Some(&menu)); - self.works.replace(self.db.get_work_descriptions(person.id)); - self.show_works(); - - self.show_recordings(); - - self.stack.set_visible_child_name("person_screen"); - self.leaflet.set_visible_child(&self.stack); + // let result = self.clone(); + // self.backend.get_work_descriptions(person.id, |works| { + // result.show_works(); + // result.show_recordings(); + // result.stack.set_visible_child_name("person_screen"); + // result.leaflet.set_visible_child(&result.stack); + // }); } fn show_works(&self) {