From a9d00188f48b41e713c28b862073e74c3ce41b44 Mon Sep 17 00:00:00 2001 From: yggverse Date: Fri, 13 Sep 2024 02:41:53 +0300 Subject: [PATCH] implement navigation history session save --- src/app/browser/main/tab/page/navigation.cpp | 37 ++- src/app/browser/main/tab/page/navigation.hpp | 6 +- .../main/tab/page/navigation/history.cpp | 246 ++++++++++++++++-- .../main/tab/page/navigation/history.hpp | 74 +++++- 4 files changed, 328 insertions(+), 35 deletions(-) diff --git a/src/app/browser/main/tab/page/navigation.cpp b/src/app/browser/main/tab/page/navigation.cpp index d6bed656..562097db 100644 --- a/src/app/browser/main/tab/page/navigation.cpp +++ b/src/app/browser/main/tab/page/navigation.cpp @@ -52,6 +52,7 @@ Navigation::Navigation( ); navigationHistory = Gtk::make_managed( + db, ACTION__NAVIGATION_HISTORY_BACK, ACTION__NAVIGATION_HISTORY_FORWARD ); @@ -135,6 +136,13 @@ int Navigation::restore( while (sqlite3_step(statement) == SQLITE_ROW) { // Restore children components + navigationHistory->restore( + sqlite3_column_int64( + statement, + DB::SESSION::ID + ) + ); + navigationRequest->restore( sqlite3_column_int64( statement, @@ -149,13 +157,33 @@ int Navigation::restore( ); } -int Navigation::save( +void Navigation::save( const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID ) { - return navigationRequest->save( + // Delete previous session + DB::SESSION::clean( + db, + APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID + ); + + // Create new record + const sqlite3_int64 APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID = DB::SESSION::add( + db, + APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID + ); + + // Delegate save action to children components + navigationHistory->save( DB::SESSION::add( db, - APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ) + ); + + navigationRequest->save( + DB::SESSION::add( + db, + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID ) ); } @@ -275,7 +303,8 @@ int Navigation::DB::SESSION::clean( db, Glib::ustring::sprintf( R"SQL( - SELECT * FROM `app_browser_main_tab_page_navigation__session` WHERE `app_browser_main_tab_page__session__id` = %d + SELECT * FROM `app_browser_main_tab_page_navigation__session` + WHERE `app_browser_main_tab_page__session__id` = %d )SQL", APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID ).c_str(), diff --git a/src/app/browser/main/tab/page/navigation.hpp b/src/app/browser/main/tab/page/navigation.hpp index 2fe941e7..280fb16e 100644 --- a/src/app/browser/main/tab/page/navigation.hpp +++ b/src/app/browser/main/tab/page/navigation.hpp @@ -94,11 +94,11 @@ namespace app::browser::main::tab::page ); int restore( - const sqlite3_int64 & APP_BROWSER_MAIN_TAB__SESSION__ID + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID ); // return sqlite3_finalize status code - int save( - const sqlite3_int64 & APP_BROWSER_MAIN_TAB__SESSION__ID + void save( + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE__SESSION__ID ); void history_add( diff --git a/src/app/browser/main/tab/page/navigation/history.cpp b/src/app/browser/main/tab/page/navigation/history.cpp index 978c9974..138253ca 100644 --- a/src/app/browser/main/tab/page/navigation/history.cpp +++ b/src/app/browser/main/tab/page/navigation/history.cpp @@ -5,9 +5,16 @@ using namespace app::browser::main::tab::page::navigation; History::History( + sqlite3 * db, const Glib::RefPtr & ACTION__HISTORY_BACK, const Glib::RefPtr & ACTION__HISTORY_FORWARD ) { + // Init database + DB::SESSION::init( + this->db = db + ); + + // Init widget add_css_class( "linked" // merge children elements ); @@ -30,6 +37,106 @@ History::History( } // Actions +void History::add( + const Glib::ustring & REQUEST, + const bool & UPDATE_MEMORY_INDEX +) { + memory.push_back( + { + REQUEST, + std::time( + nullptr + ) + } + ); + + if (UPDATE_MEMORY_INDEX) + { + index = memory.size() - 1; + } +} + +int History::restore( + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__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_tab_page_navigation_history__session` + WHERE `app_browser_main_tab_page_navigation__session__id` = %d + ORDER BY `id` DESC LIMIT 1 + )SQL", + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ).c_str(), + -1, + SQLITE_PREPARE_NORMALIZE, + &statement, + nullptr + ); + + if (PREPARE_STATUS == SQLITE_OK) + { + // Use latest record as order + while (sqlite3_step(statement) == SQLITE_ROW) + { + // Cleanup + memory.clear(); + + // Restore + memory.push_back( + { + reinterpret_cast( + sqlite3_column_text( + statement, + DB::SESSION::REQUEST + ) + ), + sqlite3_column_int( + statement, + DB::SESSION::TIME + ) + } + ); + + if (sqlite3_column_int(statement, DB::SESSION::IS_CURRENT) == 1) + { + index = memory.size() - 1; + } + + // Restore children components here (on available) + } + } + + return sqlite3_finalize( + statement + ); +} + +void History::save( + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID +) { + // Delete previous records for session + DB::SESSION::clean( + db, + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ); + + // Add new records + for (const auto & VALUE : memory) + { + DB::SESSION::add( + db, + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID, + VALUE.time, + VALUE.request, + -1 == index // @TODO + ); + } +} + void History::update() { Memory match; @@ -49,26 +156,6 @@ void History::update() ); } -void History::add( - const Glib::ustring & REQUEST, - const bool & UPDATE_MEMORY_INDEX -) { - memory.push_back( - { - REQUEST, - std::time( - nullptr - ), - true - } - ); - - if (UPDATE_MEMORY_INDEX) - { - index = memory.size() - 1; - } -} - bool History::try_back( Memory & match, const bool & UPDATE_MEMORY_INDEX @@ -115,4 +202,123 @@ bool History::try_forward( { return false; } +} + +// Database model +int History::DB::SESSION::init( + sqlite3 * db +) { + char * error; + + return sqlite3_exec( + db, + R"SQL( + CREATE TABLE IF NOT EXISTS `app_browser_main_tab_page_navigation_history__session` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `app_browser_main_tab_page_navigation__session__id` INTEGER NOT NULL, + `time` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, + `request` VARCHAR (1024) NOT NULL, + `is_current` INTEGER NOT NULL + ) + )SQL", + nullptr, + nullptr, + &error + ); +} + +int History::DB::SESSION::clean( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__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_tab_page_navigation_history__session` + WHERE `app_browser_main_tab_page_navigation__session__id` = %d + )SQL", + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ).c_str(), + -1, + SQLITE_PREPARE_NORMALIZE, + &statement, + nullptr + ); + + if (PREPARE_STATUS == SQLITE_OK) + { + while (sqlite3_step(statement) == SQLITE_ROW) + { + // Delete record + const int EXEC_STATUS = sqlite3_exec( + db, + Glib::ustring::sprintf( + R"SQL( + DELETE FROM `app_browser_main_tab_page_navigation_history__session` WHERE `id` = %d + )SQL", + sqlite3_column_int64( + statement, + DB::SESSION::ID + ) + ).c_str(), + nullptr, + nullptr, + &error + ); + + // Delegate children dependencies cleanup + if (EXEC_STATUS == SQLITE_OK) + { + // nothing here. + } + } + } + + return sqlite3_finalize( + statement + ); +} + +sqlite3_int64 History::DB::SESSION::add( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID, + const int & TIME, + const Glib::ustring & REQUEST, + const bool & IS_CURRENT +) { + char * error; // @TODO + + sqlite3_exec( + db, + Glib::ustring::sprintf( + R"SQL( + INSERT INTO `app_browser_main_tab_page_navigation_history__session` ( + `app_browser_main_tab_page_navigation__session__id`, + `time`, + `request`, + `is_current` + ) VALUES ( + '%d', + '%d', + '%s', + '%d' + ) + )SQL", + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID, + TIME, + REQUEST, + IS_CURRENT + ).c_str(), + nullptr, + nullptr, + &error + ); + + return sqlite3_last_insert_rowid( + db + ); } \ No newline at end of file diff --git a/src/app/browser/main/tab/page/navigation/history.hpp b/src/app/browser/main/tab/page/navigation/history.hpp index 1a9b8186..5803fbf5 100644 --- a/src/app/browser/main/tab/page/navigation/history.hpp +++ b/src/app/browser/main/tab/page/navigation/history.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace app::browser::main::tab::page::navigation @@ -20,26 +21,77 @@ namespace app::browser::main::tab::page::navigation class History : public Gtk::Box { - // Components - history::Back * historyBack; - history::Forward * historyForward; + private: + /* + * History class database + * + * Allowed parental access to enums and relationship methods + */ + struct DB + { + // APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION_REQUEST__* + struct SESSION + { + enum + { + ID, + APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID, + TIME, + REQUEST, + IS_CURRENT + }; // table fields index - int index = -1; + static int init( + sqlite3 * db + ); // return sqlite3_exec status code + static int clean( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ); // return sqlite3_finalize status code + + static sqlite3_int64 add( + sqlite3 * db, + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID, + const int & TIME, + const Glib::ustring & REQUEST, + const bool & IS_CURRENT + ); // return sqlite3_last_insert_rowid + }; + }; + + /* + * Internal members + */ + private: + + // Database + sqlite3 * db; + + // Components + history::Back * historyBack; + history::Forward * historyForward; + + // Extras + int index = -1; + + /* + * History class API + */ public: // Extras struct Memory { Glib::ustring request; - std::time_t time; // event unix time - bool permanent; // save in database (on application close) @TODO + std::time_t time; // event unix time }; // Define navigation history storage std::vector memory; History( + sqlite3 * db, const Glib::RefPtr & ACTION__HISTORY_BACK, const Glib::RefPtr & ACTION__HISTORY_FORWARD ); @@ -50,9 +102,15 @@ namespace app::browser::main::tab::page::navigation const bool & UPDATE_MEMORY_INDEX ); - void update(); + int restore( + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ); // return sqlite3_finalize status code - void save(); // @TODO save history to the permanent storage + void save( + const sqlite3_int64 & APP_BROWSER_MAIN_TAB_PAGE_NAVIGATION__SESSION__ID + ); + + void update(); bool try_back( Memory & match,