From c13cc44a59a564ea532bdf4504a9d89b5734cf5f Mon Sep 17 00:00:00 2001 From: yggverse Date: Thu, 12 Sep 2024 23:28:58 +0300 Subject: [PATCH] implement browser, main widget db session --- src/app/browser.cpp | 213 ++++++++++++++++++++++++++++++++++- src/app/browser.hpp | 68 ++++++++++- src/app/browser/main.cpp | 191 +++++++++++++++++++++++++++++-- src/app/browser/main.hpp | 70 ++++++++++-- src/app/browser/main/tab.cpp | 58 +++++----- src/app/browser/main/tab.hpp | 14 ++- 6 files changed, 552 insertions(+), 62 deletions(-) diff --git a/src/app/browser.cpp b/src/app/browser.cpp index 7366123..b0dc132 100644 --- a/src/app/browser.cpp +++ b/src/app/browser.cpp @@ -8,6 +8,11 @@ Browser::Browser( sqlite3 * db, const Glib::RefPtr & APP ) { + // Init database + DB::SESSION::init( + this->db = db + ); + // Init window actions const auto ACTION__UPDATE = add_action( "update", @@ -26,7 +31,7 @@ Browser::Browser( "clean", [this] { - browserMain->clean(); + clean(); } ); @@ -34,7 +39,7 @@ Browser::Browser( "restore", [this] { - browserMain->restore(); + restore(); } ); @@ -42,7 +47,7 @@ Browser::Browser( "save", [this] { - browserMain->save(); + save(); } ); @@ -232,10 +237,17 @@ Browser::Browser( ); // Connect signals + signal_realize().connect( + [this] + { + restore(); // last session from DB + } + ); + signal_close_request().connect( [this] { - browserMain->save(); + save(); // @TODO sqlite3_close(db); @@ -243,4 +255,197 @@ Browser::Browser( }, true ); +} + +// Actions +int Browser::restore() +{ + sqlite3_stmt* statement; // @TODO move to the DB model namespace + + const int PREPARE_STATUS = sqlite3_prepare_v3( + db, + R"SQL( + SELECT * FROM `app_browser__session` ORDER BY `page_number` ASC + )SQL", + -1, + SQLITE_PREPARE_NORMALIZE, + &statement, + nullptr + ); + + if (PREPARE_STATUS == SQLITE_OK) + { + while (sqlite3_step(statement) == SQLITE_ROW) + { + // Restore widget settings + set_default_size( // @TODO actualize + sqlite3_column_int( + statement, + DB::SESSION::WIDTH + ), + sqlite3_column_int( + statement, + DB::SESSION::HEIGHT + ) + ); + + // Restore children components + browserMain->restore( + sqlite3_column_int( + statement, + DB::SESSION::ID + ) + ); + } + } + + return sqlite3_finalize( + statement + ); +} + +void Browser::clean() +{ + DB::SESSION::clean( + db + ); +} + +void Browser::save() +{ + char * error; // @TODO + + // Delete previous data + DB::SESSION::clean( + db + ); // @TODO run on background + + // Create new session + const sqlite3_int64 APP_BROWSER__SESSION__ID = DB::SESSION::add( + db, + get_width(), + get_height(), + false // @TODO full screen status + ); + + // Delegate save actions to children components + browserMain->save( + APP_BROWSER__SESSION__ID + ); +} + +// Database +int Browser::DB::SESSION::init( + sqlite3 * db +) { + char * error; + + return sqlite3_exec( + db, + R"SQL( + CREATE TABLE IF NOT EXISTS `app_browser__session` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `time` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, + `width` INTEGER NOT NULL, + `height` INTEGER NOT NULL, + `is_full_screen` INTEGER NOT NULL + ) + )SQL", + nullptr, + nullptr, + &error + ); +} + +int Browser::DB::SESSION::clean( + sqlite3 * db +) { + char * error; // @TODO + sqlite3_stmt * statement; + + const int PREPARE_STATUS = sqlite3_prepare_v3( + db, + R"SQL( + SELECT * FROM `app_browser__session` + )SQL", + -1, + SQLITE_PREPARE_NORMALIZE, + &statement, + nullptr + ); + + if (PREPARE_STATUS == SQLITE_OK) + { + while (sqlite3_step(statement) == SQLITE_ROW) + { + const sqlite3_int64 APP_BROWSER__SESSION__ID = sqlite3_column_int64( + statement, + DB::SESSION::ID + ); + + // Delete record + const int EXEC_STATUS = sqlite3_exec( + db, + Glib::ustring::sprintf( + R"SQL( + DELETE FROM `app_browser__session` WHERE `id` = %d + )SQL", + APP_BROWSER__SESSION__ID + ).c_str(), + nullptr, + nullptr, + &error + ); + + // Delegate children dependencies cleanup + if (EXEC_STATUS == SQLITE_OK) + { + browser::Main::DB::SESSION::clean( + db, + APP_BROWSER__SESSION__ID + ); + } + } + } + + return sqlite3_finalize( + statement + ); +} + +sqlite3_int64 Browser::DB::SESSION::add( + sqlite3 * db, + const int & WIDTH, + const int & HEIGHT, + const bool & IS_FULL_SCREEN +) { + char * error; // @TODO + + sqlite3_exec( + db, + Glib::ustring::sprintf( + R"SQL( + INSERT INTO `app_browser__session` ( + `width`, + `height`, + `is_full_screen` + ) VALUES ( + %d, + %d, + %d + ) + )SQL", + WIDTH, + HEIGHT, + IS_FULL_SCREEN ? 1 : 0 + ).c_str(), + nullptr, + nullptr, + &error + ); + + return sqlite3_last_insert_rowid( + db + ); } \ No newline at end of file diff --git a/src/app/browser.hpp b/src/app/browser.hpp index 547644c..25a2a24 100644 --- a/src/app/browser.hpp +++ b/src/app/browser.hpp @@ -24,20 +24,76 @@ namespace app class Browser : public Gtk::ApplicationWindow { - // Components - app::browser::Header * browserHeader; - app::browser::Main * browserMain; + public: + + /* + * Tab class database + * + * Allowed parental access to enums and relationship methods + */ + struct DB + { + // APP_BROWSER_MAIN_TAB__* + struct SESSION + { + enum + { + ID, + TIME, + WIDTH, + HEIGHT, + IS_FULL_SCREEN + }; // table fields index + + static int init( + sqlite3 * db + ); // return sqlite3_exec status code + + static int clean( + sqlite3 * db + ); // return sqlite3_finalize status code + + static sqlite3_int64 add( + sqlite3 * db, + const int & WIDTH, + const int & HEIGHT, + const bool & IS_FULL_SCREEN + ); // return sqlite3_last_insert_rowid + }; + }; + + /* + * Internal members + */ + private: - // Defaults - const int WIDTH = 640; - const int HEIGHT = 480; + // Database + sqlite3 * db; + // Components + app::browser::Header * browserHeader; + app::browser::Main * browserMain; + + // Defaults + const int WIDTH = 640; + const int HEIGHT = 480; + + /* + * Browser class API + */ public: Browser( sqlite3 * db, const Glib::RefPtr & APP ); + + // Actions + int restore(); // return sqlite3_finalize status code + + void clean(); + + void save(); }; } diff --git a/src/app/browser/main.cpp b/src/app/browser/main.cpp index afd194f..7785024 100644 --- a/src/app/browser/main.cpp +++ b/src/app/browser/main.cpp @@ -12,6 +12,11 @@ Main::Main( const Glib::RefPtr & ACTION__MAIN_TAB_PAGE_NAVIGATION_HISTORY_FORWARD, const Glib::RefPtr & ACTION__MAIN_TAB_PAGE_NAVIGATION_RELOAD ) { + // Init database + DB::SESSION::init( + this->db = db + ); + // Init widget set_orientation( Gtk::Orientation::VERTICAL @@ -40,19 +45,73 @@ Main::Main( // Actions /// Session -void Main::clean() -{ - mainTab->clean(); +void Main::clean( + const sqlite3_int64 & APP_BROWSER__SESSION__ID +) { + DB::SESSION::clean( + db, + APP_BROWSER__SESSION__ID + ); + + mainTab->close_all(); }; -void Main::restore() -{ - mainTab->restore(); +int Main::restore( + const sqlite3_int64 & APP_BROWSER__SESSION__ID +) { + sqlite3_stmt* statement; // @TODO move to the DB model namespace + + const int PREPARE_STATUS = sqlite3_prepare_v3( + db, + Glib::ustring::sprintf( + R"SQL( + SELECT * FROM `app_browser_main__session` + WHERE `app_browser__session_id` = %d + )SQL", + APP_BROWSER__SESSION__ID + ).c_str(), + -1, + SQLITE_PREPARE_NORMALIZE, + &statement, + nullptr + ); + + if (PREPARE_STATUS == SQLITE_OK) + { + while (sqlite3_step(statement) == SQLITE_ROW) + { + mainTab->restore( + DB::SESSION::ID + ); + } + } + + return sqlite3_finalize( + statement + ); }; -void Main::save() -{ - mainTab->save(); +void Main::save( + const sqlite3_int64 & APP_BROWSER__SESSION__ID +) { + char * error; // @TODO + + // Delete previous data + DB::SESSION::clean( + db, + APP_BROWSER__SESSION__ID + ); // @TODO run on background + + // Create new session + const sqlite3_int64 APP_BROWSER_MAIN__SESSION__ID = DB::SESSION::add( + db, + APP_BROWSER__SESSION__ID + ); + + // Delegate save actions to children components + mainTab->save( + APP_BROWSER_MAIN__SESSION__ID + ); }; /// Tab actions @@ -130,4 +189,116 @@ Glib::ustring Main::get_tab_page_description() return mainTab->get_page_description( mainTab->get_current_page() ); -}; \ No newline at end of file +}; + + +// Database +int Main::DB::SESSION::init( + sqlite3 * db +) { + char * error; + + return sqlite3_exec( + db, + R"SQL( + CREATE TABLE IF NOT EXISTS `app_browser_main__session` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `time` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, + `app_browser__session__id` INTEGER NOT NULL + ) + )SQL", + nullptr, + nullptr, + &error + ); +} + +int Main::DB::SESSION::clean( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER__SESSION__ID +) { + char * error; // @TODO + sqlite3_stmt * statement; + + const int PREPARE_STATUS = sqlite3_prepare_v3( + db, + Glib::ustring::sprintf( + R"SQL( + SELECT * FROM `app_browser_main__session` + WHERE `app_browser__session__id` = %d + )SQL", + APP_BROWSER__SESSION__ID + ).c_str(), + -1, + SQLITE_PREPARE_NORMALIZE, + &statement, + nullptr + ); + + if (PREPARE_STATUS == SQLITE_OK) + { + while (sqlite3_step(statement) == SQLITE_ROW) + { + const sqlite3_int64 APP_BROWSER_MAIN__SESSION__ID = sqlite3_column_int64( + statement, + DB::SESSION::ID + ); + + // Delete record + const int EXEC_STATUS = sqlite3_exec( + db, + Glib::ustring::sprintf( + R"SQL( + DELETE FROM `app_browser_main__session` WHERE `id` = %d + )SQL", + APP_BROWSER_MAIN__SESSION__ID + ).c_str(), + nullptr, + nullptr, + &error + ); + + // Delegate children dependencies cleanup + if (EXEC_STATUS == SQLITE_OK) + { + main::Tab::DB::SESSION::clean( + db, + APP_BROWSER_MAIN__SESSION__ID + ); + } + } + } + + return sqlite3_finalize( + statement + ); +} + +sqlite3_int64 Main::DB::SESSION::add( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER__SESSION__ID +) { + char * error; // @TODO + + sqlite3_exec( + db, + Glib::ustring::sprintf( + R"SQL( + INSERT INTO `app_browser_main__session` ( + `app_browser_main__session__id` + ) VALUES ( + %d + ) + )SQL", + APP_BROWSER__SESSION__ID + ).c_str(), + nullptr, + nullptr, + &error + ); + + return sqlite3_last_insert_rowid( + db + ); +} \ No newline at end of file diff --git a/src/app/browser/main.hpp b/src/app/browser/main.hpp index 0b2d8fe..e1b42cf 100644 --- a/src/app/browser/main.hpp +++ b/src/app/browser/main.hpp @@ -18,12 +18,58 @@ namespace app::browser class Main : public Gtk::Box { - // Components - main::Tab * mainTab; + public: + + /* + * Tab class database + * + * Allowed parental access to enums and relationship methods + */ + struct DB + { + // APP_BROWSER_MAIN__* + struct SESSION + { + enum + { + ID, + TIME + }; // table fields index + + static int init( + sqlite3 * db + ); // return sqlite3_exec status code + + static int clean( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER__SESSION__ID + ); // return sqlite3_finalize status code + + static sqlite3_int64 add( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER__SESSION__ID + ); // return sqlite3_last_insert_rowid + + }; + }; + + /* + * Internal members + */ + private: + + // Database + sqlite3 * db; - // Defaults - const bool HOMOGENEOUS = true; + // Components + main::Tab * mainTab; + // Defaults + const bool HOMOGENEOUS = true; + + /* + * Main class API + */ public: Main( @@ -37,10 +83,6 @@ namespace app::browser ); // Actions - void clean(); - void restore(); - void save(); - void tab_append(); void tab_close_all(); @@ -52,6 +94,18 @@ namespace app::browser void tab_page_navigation_history_back(); void tab_page_navigation_history_forward(); + int restore( + const sqlite3_int64 & APP_BROWSER__SESSION__ID + ); // return sqlite3_finalize status code + + void clean( + const sqlite3_int64 & APP_BROWSER__SESSION__ID + ); + + void save( + const sqlite3_int64 & APP_BROWSER__SESSION__ID + ); + void update(); // Getters diff --git a/src/app/browser/main/tab.cpp b/src/app/browser/main/tab.cpp index af1b588..023b7cd 100644 --- a/src/app/browser/main/tab.cpp +++ b/src/app/browser/main/tab.cpp @@ -31,14 +31,6 @@ Tab::Tab( SCROLLABLE ); - // Init events - signal_realize().connect( - [this] - { - restore(); // last session from DB - } - ); - signal_switch_page().connect( [this](Gtk::Widget*, guint) { @@ -48,15 +40,20 @@ Tab::Tab( ); } -int Tab::restore() -{ +int Tab::restore( + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID +) { sqlite3_stmt* statement; // @TODO move to the DB model namespace const int PREPARE_STATUS = sqlite3_prepare_v3( db, - R"SQL( - SELECT * FROM `app_browser_main_tab__session` ORDER BY `page_number` ASC - )SQL", + Glib::ustring::sprintf( + R"SQL( + SELECT * FROM `app_browser_main_tab__session` + WHERE `app_browser_main__session_id` = %d ORDER BY `page_number` ASC + )SQL", + APP_BROWSER_MAIN__SESSION__ID + ).c_str(), -1, SQLITE_PREPARE_NORMALIZE, &statement, @@ -103,22 +100,15 @@ int Tab::restore() ); } -void Tab::clean() // @TODO menu action? -{ - DB::SESSION::clean( - db - ); - - close_all(); -} - -void Tab::save() -{ +void Tab::save( + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID +) { char * error; // @TODO // Delete previous data DB::SESSION::clean( - db + db, + APP_BROWSER_MAIN__SESSION__ID ); // @TODO run on background // Save current tab session @@ -127,6 +117,7 @@ void Tab::save() // Create new session const sqlite3_int64 APP_BROWSER_MAIN_TAB__SESSION__ID = DB::SESSION::add( db, + APP_BROWSER_MAIN__SESSION__ID, page_number, page_number == get_current_page() ? 1 : 0 ); @@ -377,16 +368,21 @@ int Tab::DB::SESSION::init( } int Tab::DB::SESSION::clean( - sqlite3 * db + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID ) { char * error; // @TODO sqlite3_stmt * statement; const int PREPARE_STATUS = sqlite3_prepare_v3( db, - R"SQL( - SELECT * FROM `app_browser_main_tab__session` - )SQL", + Glib::ustring::sprintf( + R"SQL( + SELECT * FROM `app_browser_main_tab__session` + WHERE `app_browser_main_tab__session_id` = %d + )SQL", + APP_BROWSER_MAIN__SESSION__ID + ).c_str(), -1, SQLITE_PREPARE_NORMALIZE, &statement, @@ -439,6 +435,7 @@ int Tab::DB::SESSION::clean( sqlite3_int64 Tab::DB::SESSION::add( sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID, const int & PAGE_NUMBER, const bool & IS_CURRENT ) { @@ -449,13 +446,16 @@ sqlite3_int64 Tab::DB::SESSION::add( Glib::ustring::sprintf( R"SQL( INSERT INTO `app_browser_main_tab__session` ( + `app_browser_main__session_id`, `page_number`, `is_current` ) VALUES ( + %d, %d, %d ) )SQL", + APP_BROWSER_MAIN__SESSION__ID, PAGE_NUMBER, IS_CURRENT ).c_str(), diff --git a/src/app/browser/main/tab.hpp b/src/app/browser/main/tab.hpp index e5878d7..17b99a7 100644 --- a/src/app/browser/main/tab.hpp +++ b/src/app/browser/main/tab.hpp @@ -43,11 +43,13 @@ namespace app::browser::main ); // return sqlite3_exec status code static int clean( - sqlite3 * db + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID ); // return sqlite3_finalize status code static sqlite3_int64 add( sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID, const int & PAGE_NUMBER, const bool & IS_CURRENT ); // return sqlite3_last_insert_rowid @@ -121,11 +123,13 @@ namespace app::browser::main const int & PAGE_NUMBER ); - int restore(); // return sqlite3_finalize status code + int restore( + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID + ); // return sqlite3_finalize status code - void clean(); - - void save(); + void save( + const sqlite3_int64 & APP_BROWSER_MAIN__SESSION__ID + ); // Getters Glib::ustring get_page_title(