window system rewrite

This commit is contained in:
djkato 2023-04-15 19:02:23 +02:00
parent 62fa057daf
commit de2504cdb1
6 changed files with 458 additions and 374 deletions

View file

@ -1,9 +1,7 @@
use super::csv_handler::{DataEntry, ImportedData};
use super::database_handler::{DBLoginData, QueryResult, Table, TableField, Tables};
use super::parser::parse;
use sqlx::mysql::MySqlQueryResult;
use sqlx::MySqlConnection;
use std::error::Error;
use std::sync::Arc;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::sync::{oneshot, Mutex, MutexGuard};
@ -43,12 +41,7 @@ impl BackendManger {
}
}
}
Communication::AreCreditentialsValidated(sender) => sender
.send(self.db_login_data.is_verified)
.unwrap_or_else(|e| {
println!("Server - Failed answering if credit. validated");
}),
Communication::LoadImportFilePath(path, sender) => {
Communication::LoadImportFilePath(path) => {
self.imported_data.path = path;
match self.imported_data.load_csv() {
Ok(_) => {
@ -57,21 +50,19 @@ impl BackendManger {
data.are_headers = self.imported_data.are_headers.clone();
data.data = self.imported_data.data.clone();
data.path = self.imported_data.path.clone();
drop(data);
sender.send(true).unwrap_or_else(|err| {
println!("Server - failed to send loaded file callback, {}", err)
})
}
Err(e) => {
println!("{}", e);
sender.send(false).unwrap_or_else(|e| {
println!("Server - Failed answering if imported{}", e)
})
}
}
}
Communication::GetTableDescription(table_index, sender) => {
Communication::ImportDBEntries(usize) => {
todo!()
}
Communication::SaveCSV(path) => {
todo!()
}
Communication::GetTableDescription(table_index) => {
let mut db_table_data = self.db_table_data.lock().await;
let mut csv_data = self.csv_data.lock().await;
db_table_data
@ -80,13 +71,14 @@ impl BackendManger {
.unwrap()
.describe_table(&mut self.db_connection.as_mut().unwrap())
.await;
if csv_data.are_headers {
match try_match_headers_to_fields(
&mut db_table_data,
table_index,
&csv_data.data.iter_row(0),
) {
Ok(_) => {
/* If some got automapped, try to parse them all */
for (col_index, field) in db_table_data
.tables
.get_mut(table_index)
@ -116,22 +108,15 @@ impl BackendManger {
csv_data.is_parsed = true;
}
}
sender.send(true).unwrap_or_else(|e| {
println!(
"Server - failed to respond to getTableDescription, {}",
e
)
});
}
Err(_) => sender.send(false).unwrap_or_else(|e| {
println!("Server - failed to respond to getTableDescription, {}", e)
}),
Err(_) => (),
}
} else {
sender.send(false).unwrap_or_else(|e| {
println!("Server - failed to respond to getTableDescription, {}", e)
});
}
Communication::RemoveRow(usize) => {
todo!()
}
Communication::RemoveCol(usize) => {
todo!()
}
Communication::TryParseCol(col_index) => {
let mut csv_data = self.csv_data.lock().await;
@ -261,9 +246,12 @@ pub enum Communication {
DBLoginData,
oneshot::Sender<Result<(), Box<dyn std::error::Error + Send>>>,
),
AreCreditentialsValidated(oneshot::Sender<bool>),
LoadImportFilePath(String, oneshot::Sender<bool>),
GetTableDescription(usize, oneshot::Sender<bool>),
LoadImportFilePath(String),
GetTableDescription(usize),
ImportDBEntries(usize),
RemoveCol(usize),
RemoveRow(usize),
SaveCSV(String),
TryParseCol(usize),
StartInserting(usize, Sender<QueryResult>, oneshot::Sender<bool>),
TryCommit(oneshot::Sender<QueryResult>),

View file

@ -1,14 +1,14 @@
use crate::backend::csv_handler::DataEntry;
use core::num::ParseIntError;
use eframe::glow::Query;
use sqlx::mysql::MySqlQueryResult;
use sqlx::{mysql::MySqlConnectOptions, ConnectOptions};
use sqlx::{FromRow, MySqlConnection};
use sqlx::{Executor, FromRow, MySqlConnection};
use std::error::Error;
use std::slice::Iter;
#[derive(Default)]
pub struct Tables {
pub tables: Vec<Table>,
pub current_working_table: Option<usize>,
pub is_connection_verified: bool,
}
#[derive(Default, Clone)]
@ -43,8 +43,10 @@ impl Tables {
.fetch_all(connection)
.await
.unwrap();
let mut table_i = 0;
for table in qr_tables {
println!(" >Found table:{}. {}", &table_i, &table.tables_in_quotes);
table_i += 1;
self.tables.push({
Table {
name: table.tables_in_quotes,
@ -59,23 +61,23 @@ impl Tables {
impl Table {
pub async fn transaction_commit(connection: &mut MySqlConnection) -> QueryResult {
match sqlx::query("COMMIT").execute(connection).await {
match connection.execute("COMMIT").await {
Ok(res) => {
return QueryResult {
query: "ROLLBACK".to_owned(),
query: "COMMIT".to_owned(),
result: Ok(res),
}
}
Err(e) => {
return QueryResult {
query: "ROLLBACK".to_owned(),
query: "COMMIT".to_owned(),
result: Err(Box::new(e)),
}
}
}
}
pub async fn transaction_rollback(connection: &mut MySqlConnection) -> QueryResult {
match sqlx::query("ROLLBACK").execute(connection).await {
match connection.execute("ROLLBACK").await {
Ok(res) => {
return QueryResult {
query: "ROLLBACK".to_owned(),
@ -91,16 +93,24 @@ impl Table {
}
}
pub async fn start_transaction(connection: &mut MySqlConnection) -> QueryResult {
match sqlx::query("BEGIN").execute(connection).await {
match connection.execute("SET autocommit = OFF").await {
Ok(_) => match connection.execute("BEGIN").await {
Ok(res) => {
return QueryResult {
query: "ROLLBACK".to_owned(),
query: "BEGIN".to_owned(),
result: Ok(res),
}
}
Err(e) => {
return QueryResult {
query: "ROLLBACK".to_owned(),
query: "BEGIN".to_owned(),
result: Err(Box::new(e)),
}
}
},
Err(e) => {
return QueryResult {
query: "SET autocommit = OFF".to_owned(),
result: Err(Box::new(e)),
}
}
@ -127,6 +137,7 @@ impl Table {
row.1 + "\'" + next_row.data.as_str() + "\', ",
)
});
/* remove last ", " from both */
fields.0.pop();
fields.0.pop();
fields.1.pop();
@ -187,7 +198,7 @@ pub struct QueryResult {
pub result: Result<MySqlQueryResult, Box<dyn Error + Send>>,
}
#[derive(Default, Clone)]
#[derive(Default, Clone, Debug)]
pub struct DBLoginData {
pub user_name: String,
pub database: String,

View file

@ -1,15 +1,16 @@
use super::window_manager::{CSQLWindow, ExitStatus};
use crate::backend::backend_manager::Communication;
use crate::backend::database_handler::DBLoginData;
use egui::{Context, Ui, Vec2};
use tokio::sync::mpsc::Sender;
use tokio::sync::oneshot;
pub struct DBLoginWindow {
db_login_data: DBLoginData,
sender: Sender<Communication>,
are_creditentials_verified_receiver:
Option<oneshot::Receiver<Result<(), Box<dyn std::error::Error + Send>>>>,
are_creditentials_verified_error: Option<Box<dyn std::error::Error + Send>>,
are_creditentials_verified: Option<Result<(), Box<dyn std::error::Error + Send>>>,
debug_autoconnect_sent: bool,
}
impl DBLoginWindow {
pub fn default(sender: Sender<Communication>) -> DBLoginWindow {
@ -25,23 +26,18 @@ impl DBLoginWindow {
},
sender,
are_creditentials_verified_receiver: None,
are_creditentials_verified_error: None,
are_creditentials_verified: None,
debug_autoconnect_sent: false,
}
}
}
impl DBLoginWindow {
pub fn show(&mut self, ctx: &Context, ui: &mut Ui, is_db_connection_verified: bool) {
let alignment: egui::Align2;
match is_db_connection_verified {
true => {
alignment = egui::Align2::CENTER_TOP;
}
false => {
alignment = egui::Align2::CENTER_CENTER;
}
}
impl CSQLWindow for DBLoginWindow {
fn refresh(
&mut self,
ctx: &egui::Context,
_ui: &mut egui::Ui,
_frame: &mut eframe::Frame,
) -> Option<ExitStatus> {
egui::Window::new("MySQL Login")
.id(egui::Id::new("MySQL Login"))
.resizable(false)
@ -49,13 +45,27 @@ impl DBLoginWindow {
.title_bar(true)
.scroll2([false, false])
.enabled(true)
.default_open(!is_db_connection_verified)
.anchor(alignment, Vec2::ZERO)
.anchor(egui::Align2::CENTER_CENTER, Vec2::ZERO)
.show(ctx, |ui| {
self.ui(ctx, ui);
});
if let Some(result) = &self.are_creditentials_verified {
match result {
Ok(_) => return Some(ExitStatus::Ok),
Err(e) => {
return Some(ExitStatus::Err(Box::from(<String as Into<
Box<dyn std::error::Error>,
>>::into(
e.to_string()
))))
}
}
} else {
return None;
}
}
}
impl DBLoginWindow {
fn ui(&mut self, ctx: &Context, ui: &mut Ui) {
ui.heading("Log into the database:");
ui.group(|ui| {
@ -92,6 +102,21 @@ impl DBLoginWindow {
ui.horizontal(|ui| {
ui.checkbox(&mut self.db_login_data.should_remember, "Remember");
/* Autoconnects in debug mode */
if cfg!(debug_assertions) && !self.debug_autoconnect_sent {
println!(" * pre-connecting to \"{:?}\"...", &self.db_login_data);
let (sender, receiver) = oneshot::channel();
self.are_creditentials_verified_receiver = Some(receiver);
self.sender
.try_send(Communication::ValidateCreditentials(
self.db_login_data.clone(),
sender,
))
.unwrap_or_else(|e| {
println!("Failed to send authenticator... {}", e);
});
self.debug_autoconnect_sent = true
}
if ui.button("Connect").clicked() {
let (sender, receiver) = oneshot::channel();
self.are_creditentials_verified_receiver = Some(receiver);
@ -107,16 +132,19 @@ impl DBLoginWindow {
});
/* If db login bad, return sqlx error to UI */
if let Some(err) = &mut self.are_creditentials_verified_error {
if let Some(Err(err)) = &mut self.are_creditentials_verified {
ui.style_mut().visuals.override_text_color = Some(egui::Color32::RED);
ui.label(format!("{}", err));
} else if let Some(Ok(_)) = &self.are_creditentials_verified {
ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN);
ui.label("Connected");
}
if let Some(receiver) = &mut self.are_creditentials_verified_receiver {
if let Ok(response) = receiver.try_recv() {
match response {
Ok(_) => self.are_creditentials_verified_error = None,
Err(err) => self.are_creditentials_verified_error = Some(err),
Ok(_) => self.are_creditentials_verified = Some(Ok(())),
Err(err) => self.are_creditentials_verified = Some(Err(err)),
}
self.are_creditentials_verified_receiver = None;
}

View file

@ -7,13 +7,15 @@ use tokio::sync::oneshot;
use crate::backend::backend_manager::Communication;
use crate::backend::database_handler::QueryResult;
use super::window_manager::{CSQLWindow, ExitStatus};
pub struct DBTransactionWindow {
sender: Sender<Communication>,
/* (Query, Result) */
log_history: Vec<QueryResult>,
logs_receiver: Option<Receiver<QueryResult>>,
is_log_finished_receiver: Option<oneshot::Receiver<bool>>,
result: Option<Vec<Result<MySqlQueryResult, Box<dyn Error>>>>,
is_log_finished: bool,
is_finished: bool,
final_result_receiver: Option<oneshot::Receiver<QueryResult>>,
working_table_index: usize,
}
@ -25,16 +27,22 @@ impl DBTransactionWindow {
DBTransactionWindow {
sender,
log_history: vec![],
result: None,
is_finished: false,
logs_receiver: None,
final_result_receiver: None,
is_log_finished_receiver: None,
is_log_finished: false,
working_table_index,
}
}
}
impl DBTransactionWindow {
pub fn show(&mut self, ctx: &Context, ui: &mut Ui, frame: &mut eframe::Frame) {
impl CSQLWindow for DBTransactionWindow {
fn refresh(
&mut self,
ctx: &Context,
ui: &mut Ui,
frame: &mut eframe::Frame,
) -> Option<ExitStatus> {
egui::Window::new("Database Transactions")
.id(egui::Id::new("Database Transactions"))
.resizable(false)
@ -50,10 +58,24 @@ impl DBTransactionWindow {
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
.show(ctx, |ui| {
self.log();
self.ui(ctx, ui);
self.ui(ctx, ui, frame);
});
if self.is_finished {
return Some(ExitStatus::Ok);
}
None
}
}
impl DBTransactionWindow {
pub fn log(&mut self) {
if let Some(finish_receiver) = self.final_result_receiver.as_mut() {
if let Ok(result) = finish_receiver.try_recv() {
if result.result.is_ok() {
self.is_finished = true;
}
}
}
if self.logs_receiver.is_some() {
if let Ok(log) = self.logs_receiver.as_mut().unwrap().try_recv() {
self.log_history.push(log);
@ -61,8 +83,8 @@ impl DBTransactionWindow {
}
if self.is_log_finished_receiver.is_some() {
if let Ok(finished) = self.is_log_finished_receiver.as_mut().unwrap().try_recv() {
self.result = Some(vec![]);
println!("FINISHED THE QUERY!!!");
self.is_log_finished = finished;
println!("FINISHED QUERYING!!!");
}
}
if self.is_log_finished_receiver.is_none() && self.logs_receiver.is_none() {
@ -79,8 +101,8 @@ impl DBTransactionWindow {
.unwrap_or_else(|_| println!("Failed to send startInserting"));
}
}
pub fn ui(&mut self, ctx: &Context, ui: &mut Ui) {
ui.add_enabled_ui(self.result.is_some(), |ui| {
pub fn ui(&mut self, ctx: &Context, ui: &mut Ui, frame: &mut eframe::Frame) {
ui.add_enabled_ui(self.is_log_finished, |ui| {
ui.horizontal(|ui| {
if ui.button("Roll back").clicked() {
if self.final_result_receiver.is_none() {
@ -103,7 +125,7 @@ impl DBTransactionWindow {
});
});
/* DB Output Stuff */
egui::ScrollArea::both()
egui::ScrollArea::vertical()
.auto_shrink([false; 2])
.stick_to_bottom(true)
.show(ui, |ui| {
@ -111,9 +133,17 @@ impl DBTransactionWindow {
.striped(true)
.resizable(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::LEFT))
.column(egui_extras::Column::remainder().clip(true))
.column(
egui_extras::Column::remainder()
.clip(true)
.at_most(frame.info().window_info.size.x / 1.3 / 2.0),
)
.stick_to_bottom(true)
.column(egui_extras::Column::remainder().clip(true))
.column(
egui_extras::Column::remainder()
.clip(true)
.at_most(frame.info().window_info.size.x / 1.3 / 2.0),
)
.stick_to_bottom(true);
table
@ -155,3 +185,8 @@ impl DBTransactionWindow {
});
}
}
pub struct OptionsDBTransactionWindow {
substitute_zero_dates_for_NULL: bool,
remove_id_field_from_insert: bool,
}

View file

@ -1,23 +1,20 @@
use super::window_manager::{CSQLWindow, ExitStatus};
use crate::backend::backend_manager::Communication;
use crate::backend::csv_handler::ImportedData;
use crate::backend::database_handler::{TableField, Tables};
use egui::{ComboBox, Context, Ui};
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
use egui_extras::{Column, TableBuilder};
use std::error::Error;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::sync::{mpsc::Sender, oneshot};
use tokio::sync::mpsc::Sender;
use tokio::sync::{Mutex, MutexGuard};
pub struct SpreadSheetWindow {
sender: Sender<Communication>,
csv_data_handle: Arc<Mutex<ImportedData>>,
db_table_data_handle: Arc<Mutex<Tables>>,
is_file_loaded_receiver: Option<oneshot::Receiver<bool>>,
is_file_loaded: bool,
current_table: Option<usize>,
is_table_described_receiver: Option<oneshot::Receiver<bool>>,
is_table_described: bool,
is_table_matched_with_headers: bool,
commit_to_db_sender: Sender<usize>,
should_export_to_db: bool,
debug_autoload_file_sent: bool,
}
impl SpreadSheetWindow {
pub fn default(
@ -28,106 +25,108 @@ impl SpreadSheetWindow {
) -> SpreadSheetWindow {
SpreadSheetWindow {
sender,
is_file_loaded_receiver: None,
is_file_loaded: false,
is_table_described_receiver: None,
is_table_described: false,
is_table_matched_with_headers: false,
csv_data_handle,
db_table_data_handle,
current_table: None,
commit_to_db_sender,
debug_autoload_file_sent: false,
should_export_to_db: false,
}
}
}
impl CSQLWindow for SpreadSheetWindow {
fn refresh(
&mut self,
ctx: &egui::Context,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
) -> Option<ExitStatus> {
self.ui(ui, ctx);
if self.should_export_to_db {
self.should_export_to_db = false;
return Some(ExitStatus::StartTransactionWindow);
}
None
}
}
impl SpreadSheetWindow {
pub fn show(&mut self, ctx: &Context, ui: &mut Ui, is_db_connection_verified: bool) {
self.ui(ui, ctx, is_db_connection_verified);
}
fn ui(&mut self, ui: &mut Ui, ctx: &Context, is_db_connection_verified: bool) {
/* Program Menu */
ui.horizontal_top(|ui| {
if ui.button("Open File").clicked() {
if let Some(path) = rfd::FileDialog::new()
.add_filter("Spreadsheets", &["csv"])
.pick_file()
{
self.open_file(path.display().to_string());
};
}
if ui.button("Save File").clicked() {
println!("Saving file lol");
}
ui.add_space(ui.available_width() * 0.8);
fn ui(&mut self, ui: &mut Ui, ctx: &Context) {
/* if csv was auto mapped and parsed */
let is_csv_parsed: bool;
if let Ok(csv_data) = self.csv_data_handle.try_lock() {
is_csv_parsed = csv_data.is_parsed.clone();
} else {
is_csv_parsed = false;
}
/* Program Menu */
ui.horizontal(|ui| {
ui.group(|ui| {});
});
/* CSV & DB menu */
ui.horizontal(|ui| {
ui.columns(2, |uis| {
uis[0].group(|ui| {
if ui.button("Import file").clicked() {
self.open_file();
}
if ui.button("Save").clicked() {
self.save_file();
}
if ui.button("Save as...").clicked() {
self.save_file();
}
});
uis[1].group(|ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
self.table_options(ui);
if ui.button("Import DB").clicked() {
todo!();
}
ui.add_enabled_ui(is_csv_parsed, |ui| {
if ui.button("Commit to Database").clicked() {
self.commit_to_db_sender
.try_send(self.current_table.unwrap())
.unwrap_or_else(|_| println!("failed to send committodb-UI"))
if ui.button("Save to DB").clicked() {
self.should_export_to_db = true;
}
if ui.button("Append to DB").clicked() {
todo!();
}
});
});
/* if db isn't connected, don't allow imports */
if !is_db_connection_verified {
return;
};
});
})
});
/* Handle file drops */
ctx.input(|i| {
if !i.raw.dropped_files.is_empty() {
self.open_file(
i.raw
.dropped_files
.clone()
.get(0)
.unwrap()
.path
.as_ref()
.unwrap()
.display()
.to_string(),
);
self.open_dropped_file(i);
}
});
self.check_file();
SpreadSheetWindow::preview_files_being_dropped(ctx);
if !self.is_file_loaded {
ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file..."));
}
if self.is_file_loaded {
if self.current_table.is_none() {
ui.group(|ui| {
StripBuilder::new(ui) //So the window doesn't grow with the innerts
.size(Size::remainder().at_least(100.0)) // for the table
.vertical(|mut strip| {
strip.cell(|ui| {
egui::ScrollArea::horizontal().show(ui, |ui| self.table_options(ui));
egui::ScrollArea::horizontal().show(ui, |ui| {
self.table_builder(ui);
});
});
});
};
}
}
fn table_options(&mut self, ui: &mut Ui) {
/* Create table select option */
/* Create table select option, only enable if the tables are discovered yet*/
if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() {
let mut select_table = ComboBox::from_label("Select Table");
ui.add_enabled_ui(db_table_data.tables.get(0).is_some(), |ui| {
let mut select_table = ComboBox::from_label("Select Table").width(100.0);
if let Some(table_index) = self.current_table {
select_table = select_table
.selected_text(&db_table_data.tables.get(table_index).unwrap().name);
if let Some(current_table) = &db_table_data.tables.get(table_index) {
select_table = select_table.selected_text(current_table.name.clone());
}
}
/* autoselect oc_product in debug mode */
if cfg!(debug_assertions) && self.current_table.is_none() {
self.current_table = Some(88);
if let Some(table_88) = &db_table_data.tables.get(88) {
select_table = select_table.selected_text(table_88.name.clone());
}
}
ui.vertical(|ui| {
select_table.show_ui(ui, |ui| {
@ -140,35 +139,7 @@ impl SpreadSheetWindow {
}
});
});
/* If a table is selected, try if it's fields are discovered */
if !self.is_table_described {
if let Some(table_i) = self.current_table {
if db_table_data.tables.get(table_i).unwrap().fields.is_some() {
self.is_table_described = true;
} else if self.is_table_described_receiver.is_some() {
match self
.is_table_described_receiver
.as_mut()
.unwrap()
.try_recv()
{
Ok(res) => self.is_table_matched_with_headers = res,
Err(e) => println!("Failed receiving is_table_described, {}", e),
}
} else {
let (sender, receiver) = oneshot::channel();
self.is_table_described_receiver = Some(receiver);
self.sender
.try_send(Communication::GetTableDescription(table_i, sender))
.unwrap_or_else(|e| println!("Failed asking to describe table, {}", e));
}
}
}
}
if self.is_table_described {
self.table_builder(ui);
});
}
}
fn table_builder(&mut self, ui: &mut Ui) {
@ -186,7 +157,7 @@ impl SpreadSheetWindow {
.striped(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center));
for _i in 0..csv_data.data.cols() {
for _i in 0..csv_data.data.cols() + 1 {
table = table.column(Column::auto().resizable(true).clip(false));
}
/* If cols got prematched by name */
@ -195,61 +166,14 @@ impl SpreadSheetWindow {
.column(Column::remainder())
.min_scrolled_height(0.0)
.header(20., |mut header| {
/* First Col for row mutators */
header.col(|ui|{
ui.add_space(45.0);
});
for i in 0..csv_data.data.cols() {
header.col(|ui| {
if csv_data.parsed_cols.contains(&i){
/* If the whole col is parsed, change header bg to green, else normal */
ui.style_mut().visuals.override_text_color= Some(egui::Color32::GREEN);
} else {
ui.style_mut().visuals.override_text_color= Some(egui::Color32::RED);
}
let mut combo_box: ComboBox;
if csv_data.are_headers {
combo_box = ComboBox::new(
i,
csv_data.data.get(0, i).unwrap().data.clone(),
);
} else {
combo_box = ComboBox::new(i, "");
}
//if any field is assinged to this combobox, show it's text, else "----"
if let Some(selected_field) = curr_db_table_fields
.iter()
.find(|field| field.mapped_to_col == Some(i))
{
combo_box = combo_box
.selected_text(selected_field.description.field.clone());
} else{
combo_box = combo_box.selected_text("-----");
}
/* When a Field gets attached to Col, */
combo_box.show_ui(ui, |ui| {
for field in curr_db_table_fields.iter_mut()
{
if ui
.selectable_value(
&mut field.mapped_to_col,
Some(i),
field.description.field.clone(),
)
.clicked()
{
self.is_table_described = false;
match self.sender.try_send(Communication::TryParseCol(i)){
Ok(_) => {
for cel in csv_data.data.iter_col_mut(i) {
cel.curr_field_description =
Some(field.description.clone());
}
}
Err(e) => println!("failed sending parsecol request, {}",e)
}
}
}
});
ui.reset_style();
SpreadSheetWindow::add_header_col(ui,i, csv_data,&mut curr_db_table_fields, &mut self.sender);
});
}
})
@ -287,33 +211,125 @@ impl SpreadSheetWindow {
});
});
}
} else {
ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file..."));
}
}
}
impl SpreadSheetWindow {
pub fn check_file(&mut self) {
if let Some(receiver) = &mut self.is_file_loaded_receiver {
match receiver.try_recv() {
Ok(boole) => {
if boole {
self.is_file_loaded_receiver = None;
pub fn add_header_col(
ui: &mut Ui,
i: usize,
csv_data: &mut MutexGuard<ImportedData>,
curr_db_table_fields: &mut Vec<TableField>,
sender: &mut Sender<Communication>,
) {
ui.vertical_centered_justified(|ui| {
if ui.button("x").clicked() {
todo!()
}
self.is_file_loaded = boole;
if csv_data.parsed_cols.contains(&i) {
/* If the whole col is parsed, change header bg to green, else normal */
ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN);
} else {
ui.style_mut().visuals.override_text_color = Some(egui::Color32::RED);
}
Err(e) => println!("Failed receiving load file callback, {}", e),
let mut combo_box: ComboBox;
if csv_data.are_headers {
combo_box = ComboBox::new(i, csv_data.data.get(0, i).unwrap().data.clone());
} else {
combo_box = ComboBox::new(i, "");
}
//if any field is assinged to this combobox, show it's text, else "----"
if let Some(selected_field) = curr_db_table_fields
.iter()
.find(|field| field.mapped_to_col == Some(i))
{
combo_box = combo_box.selected_text(selected_field.description.field.clone());
} else {
combo_box = combo_box.selected_text("-----");
}
/* When a Field gets attached to Col, */
combo_box.show_ui(ui, |ui| {
for field in curr_db_table_fields.iter_mut() {
if ui
.selectable_value(
&mut field.mapped_to_col,
Some(i),
field.description.field.clone(),
)
.clicked()
{
match sender.try_send(Communication::TryParseCol(i)) {
Ok(_) => {
for cel in csv_data.data.iter_col_mut(i) {
cel.curr_field_description = Some(field.description.clone());
}
}
Err(e) => println!("failed sending parsecol request, {}", e),
}
}
}
});
ui.reset_style();
});
}
pub fn save_file(&mut self) {
let mut save_name = "to-csv".to_owned();
if let Some(table_i) = self.current_table {
if let Ok(db_table_data) = self.db_table_data_handle.try_lock() {
save_name = db_table_data.tables.get(table_i).unwrap().name.clone();
}
}
if let Some(path) = rfd::FileDialog::new()
.set_file_name(format!("db-{}-converted.csv", save_name).as_str())
.save_file()
{
self.sender
.try_send(Communication::SaveCSV(path.display().to_string()))
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
};
}
pub fn open_file(&mut self) {
/*preloads file in debug */
if cfg!(debug_assertions) && !self.debug_autoload_file_sent {
let path = std::path::PathBuf::from("/home/djkato/Dokumenty/csql/oc_product.csv");
println!(" * Preloading \"{:?}\"...", path);
self.debug_autoload_file_sent = true;
}
if let Some(path) = rfd::FileDialog::new()
.add_filter("Spreadsheets", &["csv"])
.pick_file()
{
self.sender
.try_send(Communication::LoadImportFilePath(
path.display().to_string(),
))
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
}
}
pub fn open_file(&mut self, path: String) {
if !self.is_file_loaded_receiver.is_some() {
let (sed, rec) = oneshot::channel();
pub fn open_dropped_file(&mut self, path: &egui::InputState) {
let path = path
.raw
.dropped_files
.clone()
.get(0)
.unwrap()
.path
.as_ref()
.unwrap()
.display()
.to_string();
self.sender
.try_send(Communication::LoadImportFilePath(path, sed))
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
self.is_file_loaded_receiver = Some(rec);
}
.try_send(Communication::LoadImportFilePath(path))
.unwrap_or_else(|err| println!("failed to send loadimportpathdropped, {}", err));
}
pub fn preview_files_being_dropped(ctx: &egui::Context) {

View file

@ -10,6 +10,7 @@ use tokio::sync::oneshot;
use tokio::sync::Mutex;
use super::db_transaction_window::DBTransactionWindow;
use super::{db_login_window, db_transaction_window};
pub fn create_ui(
sender: Sender<Communication>,
@ -32,15 +33,13 @@ pub fn create_ui(
csv_data_handle.clone(),
db_table_data_handle.clone(),
),
db_login_window: DBLoginWindow::default(sender.clone()),
db_login_window: None,
db_transaction_window: None,
is_db_connection_verified_receiver: None,
sender,
is_db_connection_verified: false,
csv_data_handle,
db_table_data_handle,
open_db_transaction_window_receiver,
should_open_db_transaction_window: None,
should_open_transaction_window: false,
should_open_login_window: true,
})
}),
)
@ -48,60 +47,67 @@ pub fn create_ui(
struct CSQL {
spreadsheet_window: SpreadSheetWindow,
db_login_window: DBLoginWindow,
db_login_window: Option<DBLoginWindow>,
db_transaction_window: Option<DBTransactionWindow>,
sender: Sender<Communication>,
is_db_connection_verified_receiver: Option<oneshot::Receiver<bool>>,
is_db_connection_verified: bool,
csv_data_handle: Arc<Mutex<ImportedData>>,
db_table_data_handle: Arc<Mutex<Tables>>,
open_db_transaction_window_receiver: Receiver<usize>,
should_open_db_transaction_window: Option<usize>,
should_open_transaction_window: bool,
should_open_login_window: bool,
}
impl App for CSQL {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
self.db_login_window
.show(ctx, ui, self.is_db_connection_verified);
self.spreadsheet_window
.show(ctx, ui, self.is_db_connection_verified);
if let Ok(resp) = self.open_db_transaction_window_receiver.try_recv() {
self.should_open_db_transaction_window = Some(resp);
if let Some(result) = self.spreadsheet_window.refresh(ctx, ui, frame) {
match result {
ExitStatus::StartLoginWindow => self.should_open_transaction_window = true,
ExitStatus::StartTransactionWindow => self.should_open_login_window = true,
_ => (),
}
};
if self.should_open_login_window {
if let Some(db_login_window) = self.db_login_window.as_mut() {
if let Some(result) = db_login_window.refresh(ctx, ui, frame) {
match result {
ExitStatus::Ok => {
self.db_login_window = None;
self.should_open_login_window = false;
}
_ => (),
}
}
}
}
if self.should_open_transaction_window {
if let Some(db_transaction_window) = self.db_transaction_window.as_mut() {
db_transaction_window.show(ctx, ui, frame)
if let Some(result) = db_transaction_window.refresh(ctx, ui, frame) {
match result {
ExitStatus::Ok => {
self.db_transaction_window = None;
self.should_open_transaction_window = false;
}
if let Some(working_table_index) = self.should_open_db_transaction_window {
let db_transaction_window =
DBTransactionWindow::default(self.sender.clone(), working_table_index);
self.db_transaction_window = Some(db_transaction_window);
self.db_transaction_window
.as_mut()
.unwrap()
.show(ctx, ui, frame);
self.should_open_db_transaction_window = None;
_ => (),
}
/* Changes self if db connection is verified */
if let Some(oneshot_receiver) = &mut self.is_db_connection_verified_receiver {
if let Ok(boole) = oneshot_receiver.try_recv() {
self.is_db_connection_verified = boole;
self.is_db_connection_verified_receiver = None;
}
} else {
let (sed, rec) = oneshot::channel();
self.is_db_connection_verified_receiver = Some(rec);
match self
.sender
.try_send(Communication::AreCreditentialsValidated(sed))
{
Ok(_) => (),
Err(e) => println!("Failed to send-verify db conn oneshot, {}", e),
}
}
});
}
}
pub trait CSQLWindow {
fn refresh(
&mut self,
ctx: &egui::Context,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
) -> Option<ExitStatus>;
}
pub enum ExitStatus {
StartTransactionWindow,
StartLoginWindow,
Ok,
Err(Box<dyn std::error::Error>),
}