From 85f0e04d0e1b06411832afcc04392e8f04434b66 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 14 Aug 2022 10:07:45 +0200 Subject: [PATCH] feat: Allow recents to also display other providers --- .../include/hex/api/content_registry.hpp | 6 +- lib/libimhex/include/hex/api/event.hpp | 2 +- lib/libimhex/include/hex/api/imhex_api.hpp | 4 +- lib/libimhex/include/hex/helpers/fs.hpp | 3 +- .../include/hex/providers/provider.hpp | 4 + lib/libimhex/source/api/imhex_api.cpp | 9 +- lib/libimhex/source/helpers/fs.cpp | 3 + lib/libimhex/source/providers/provider.cpp | 5 +- main/source/init/tasks.cpp | 24 ++-- .../content/providers/intel_hex_provider.hpp | 4 +- plugins/builtin/source/content/events.cpp | 15 +- .../content/providers/intel_hex_provider.cpp | 12 ++ .../content/views/view_provider_settings.cpp | 3 +- .../builtin/source/content/welcome_screen.cpp | 134 +++++++++++------- 14 files changed, 150 insertions(+), 78 deletions(-) diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index f16d30151..761bc12b4 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -337,12 +337,12 @@ namespace hex { void add(bool addToList = true) { auto typeName = T().getTypeName(); - (void)EventManager::subscribe([expectedName = typeName](const std::string &name, hex::prv::Provider **provider) { + (void)EventManager::subscribe([expectedName = typeName](const std::string &name, bool skipLoadInterface, hex::prv::Provider **provider) { if (name != expectedName) return; - auto newProvider = new T(); + prv::Provider *newProvider = new T(); - hex::ImHexApi::Provider::add(newProvider); + hex::ImHexApi::Provider::add(newProvider, skipLoadInterface); if (provider != nullptr) *provider = newProvider; diff --git a/lib/libimhex/include/hex/api/event.hpp b/lib/libimhex/include/hex/api/event.hpp index 7e264d068..5861c115b 100644 --- a/lib/libimhex/include/hex/api/event.hpp +++ b/lib/libimhex/include/hex/api/event.hpp @@ -129,7 +129,7 @@ namespace hex { EVENT_DEF(RequestOpenFile, std::fs::path); EVENT_DEF(RequestChangeTheme, u32); EVENT_DEF(RequestOpenPopup, std::string); - EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **); + EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **); EVENT_DEF(RequestShowInfoPopup, std::string); EVENT_DEF(RequestShowErrorPopup, std::string); diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index d97be04c7..73c2a0724 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -137,7 +137,7 @@ namespace hex { void resetDirty(); bool isDirty(); - void add(prv::Provider *provider); + void add(prv::Provider *provider, bool skipLoadInterface = false); template T> void add(auto &&...args) { @@ -146,7 +146,7 @@ namespace hex { void remove(prv::Provider *provider, bool noQuestions = false); - prv::Provider* createProvider(const std::string &unlocalizedName); + prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false); } diff --git a/lib/libimhex/include/hex/helpers/fs.hpp b/lib/libimhex/include/hex/helpers/fs.hpp index 130312316..807c48aa7 100644 --- a/lib/libimhex/include/hex/helpers/fs.hpp +++ b/lib/libimhex/include/hex/helpers/fs.hpp @@ -96,7 +96,8 @@ namespace hex::fs { Resources, Constants, Encodings, - Logs + Logs, + Recent }; std::optional getExecutablePath(); diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index 54cb0d4bb..d4701169b 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -104,6 +104,9 @@ namespace hex::prv { virtual std::pair getRegionValidity(u64 address) const; + void skipLoadInterface() { this->m_skipLoadInterface = true; } + [[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; } + protected: u32 m_currPage = 0; u64 m_baseAddress = 0; @@ -115,6 +118,7 @@ namespace hex::prv { u32 m_id; bool m_dirty = false; + bool m_skipLoadInterface = false; private: static u32 s_idCounter; diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 9c607e54c..93d725732 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -268,10 +268,13 @@ namespace hex { }); } - void add(prv::Provider *provider) { + void add(prv::Provider *provider, bool skipLoadInterface) { if (Task::getRunningTaskCount() > 0) return; + if (skipLoadInterface) + provider->skipLoadInterface(); + s_providers.push_back(provider); EventManager::post(provider); @@ -310,9 +313,9 @@ namespace hex { delete provider; } - prv::Provider* createProvider(const std::string &unlocalizedName) { + prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface) { prv::Provider* result = nullptr; - EventManager::post(unlocalizedName, &result); + EventManager::post(unlocalizedName, skipLoadInterface, &result); return result; } diff --git a/lib/libimhex/source/helpers/fs.cpp b/lib/libimhex/source/helpers/fs.cpp index 8fe1580c1..dc58ced3e 100644 --- a/lib/libimhex/source/helpers/fs.cpp +++ b/lib/libimhex/source/helpers/fs.cpp @@ -232,6 +232,9 @@ namespace hex::fs { case ImHexPath::Yara: result = appendPath(getDataPaths(), "yara"); break; + case ImHexPath::Recent: + result = appendPath(getConfigPaths(), "recent"); + break; } if (!listNonExisting) { diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index e9f927512..ccf8d1e2a 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -251,6 +251,9 @@ namespace hex::prv { } nlohmann::json Provider::storeSettings(nlohmann::json settings) const { + settings["displayName"] = this->getName(); + settings["type"] = this->getTypeName(); + settings["baseAddress"] = this->m_baseAddress; settings["currPage"] = this->m_currPage; @@ -263,7 +266,7 @@ namespace hex::prv { } std::pair Provider::getRegionValidity(u64 address) const { - if (address > this->getActualSize()) + if (address < this->getActualSize()) return { Region::Invalid(), false }; bool insideValidRegion = false; diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index 5291ddb98..6dfd6a049 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -59,18 +59,20 @@ namespace hex::init { bool createDirectories() { bool result = true; + using enum fs::ImHexPath; constexpr std::array paths = { - fs::ImHexPath::Patterns, - fs::ImHexPath::PatternsInclude, - fs::ImHexPath::Magic, - fs::ImHexPath::Plugins, - fs::ImHexPath::Resources, - fs::ImHexPath::Config, - fs::ImHexPath::Constants, - fs::ImHexPath::Yara, - fs::ImHexPath::Encodings, - fs::ImHexPath::Python, - fs::ImHexPath::Logs + Patterns, + PatternsInclude, + Magic, + Plugins, + Resources, + Config, + Constants, + Yara, + Encodings, + Python, + Logs, + Recent }; // Check if ImHex is installed in portable mode diff --git a/plugins/builtin/include/content/providers/intel_hex_provider.hpp b/plugins/builtin/include/content/providers/intel_hex_provider.hpp index 550ef26b6..07fcec49a 100644 --- a/plugins/builtin/include/content/providers/intel_hex_provider.hpp +++ b/plugins/builtin/include/content/providers/intel_hex_provider.hpp @@ -27,8 +27,8 @@ namespace hex::plugin::builtin::prv { [[nodiscard]] std::string getName() const override; [[nodiscard]] std::vector> getDataInformation() const override { return { }; } - void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); } - [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; } + void loadSettings(const nlohmann::json &settings) override; + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override; [[nodiscard]] std::string getTypeName() const override { return "hex.builtin.provider.intel_hex"; diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index b653e417a..02729f3ef 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -13,11 +13,16 @@ #include "provider_extra_data.hpp" +#include "content/providers/file_provider.hpp" + namespace hex::plugin::builtin { static void openFile(const std::fs::path &path) { - ImHexApi::Provider::createProvider("hex.builtin.provider.file"); - EventManager::post(path); + auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true); + if (auto *fileProvider = dynamic_cast(provider); fileProvider != nullptr) { + fileProvider->setPath(path); + (void)fileProvider->open(); + } } void registerEventHandlers() { @@ -77,6 +82,9 @@ namespace hex::plugin::builtin { }); EventManager::subscribe([](hex::prv::Provider *provider) { + if (provider->shouldSkipLoadInterface()) + return; + if (provider->hasFilePicker()) { if (!provider->handleFilePicker()) { ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); @@ -95,9 +103,6 @@ namespace hex::plugin::builtin { View::showErrorPopup("hex.builtin.popup.error.open"_lang); ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); } - - if (!provider->isWritable()) - View::showErrorPopup("hex.builtin.popup.error.read_only"_lang); } }); diff --git a/plugins/builtin/source/content/providers/intel_hex_provider.cpp b/plugins/builtin/source/content/providers/intel_hex_provider.cpp index 08d1644a2..2bd44fa21 100644 --- a/plugins/builtin/source/content/providers/intel_hex_provider.cpp +++ b/plugins/builtin/source/content/providers/intel_hex_provider.cpp @@ -232,4 +232,16 @@ namespace hex::plugin::builtin::prv { return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true }; } + void IntelHexProvider::loadSettings(const nlohmann::json &settings) { + Provider::loadSettings(settings); + + this->m_sourceFilePath = settings["path"].get(); + } + + nlohmann::json IntelHexProvider::storeSettings(nlohmann::json settings) const { + settings["path"] = this->m_sourceFilePath.string(); + + return Provider::storeSettings(settings); + } + } diff --git a/plugins/builtin/source/content/views/view_provider_settings.cpp b/plugins/builtin/source/content/views/view_provider_settings.cpp index b2b2765c4..a52cf2eb5 100644 --- a/plugins/builtin/source/content/views/view_provider_settings.cpp +++ b/plugins/builtin/source/content/views/view_provider_settings.cpp @@ -35,8 +35,9 @@ namespace hex::plugin::builtin { ImGui::Separator(); if (ImGui::Button("hex.builtin.common.open"_lang)) { - if (provider->open()) + if (provider->open()) { ImGui::CloseCurrentPopup(); + } else { View::showErrorPopup("hex.builtin.view.provider_settings.load_error"_lang); ImHexApi::Provider::remove(provider); diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index da39e601c..cd5812abe 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -6,18 +6,17 @@ #include #include #include +#include #include #include #include -#include #include #include #include -#include #include #include @@ -25,12 +24,74 @@ namespace hex::plugin::builtin { static ImGui::Texture s_bannerTexture, s_backdropTexture; - static std::list s_recentFilePaths; static std::fs::path s_safetyBackupPath; static std::string s_tipOfTheDay; + struct RecentProvider { + std::string displayName; + std::string type; + std::fs::path filePath; + + nlohmann::json data; + + bool operator==(const RecentProvider &other) const { + return displayName == other.displayName && type == other.type && data == other.data; + } + }; + static std::vector s_recentProviders; + + static void updateRecentProviders() { + s_recentProviders.clear(); + + // Query all recent providers + std::vector recentFiles; + for (const auto &folder : fs::getDefaultPaths(fs::ImHexPath::Recent)) { + for (const auto &entry : std::fs::directory_iterator(folder)) { + if (entry.is_regular_file()) + recentFiles.push_back(entry.path()); + } + } + + // Sort recent provider files by last modified time + std::sort(recentFiles.begin(), recentFiles.end(), [](const auto &a, const auto &b) { + return std::fs::last_write_time(a) > std::fs::last_write_time(b); + }); + + for (u32 i = 0; i < recentFiles.size() && s_recentProviders.size() < 5; i++) { + auto &path = recentFiles[i]; + try { + auto jsonData = nlohmann::json::parse(fs::File(path, fs::File::Mode::Read).readString()); + s_recentProviders.push_back(RecentProvider { + .displayName = jsonData["displayName"], + .type = jsonData["type"], + .filePath = path, + .data = jsonData + }); + } catch (...) { } + } + + // De-duplicate recent providers + s_recentProviders.erase(std::unique(s_recentProviders.begin(), s_recentProviders.end()), s_recentProviders.end()); + } + + static void loadRecentProvider(const RecentProvider &recentProvider) { + auto *provider = ImHexApi::Provider::createProvider(recentProvider.type, true); + if (provider != nullptr) { + provider->loadSettings(recentProvider.data); + + if (!provider->open() || !provider->isAvailable()) { + View::showErrorPopup("hex.builtin.popup.error.open"_lang); + ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + return; + } + + updateRecentProviders(); + } + + } + static void loadDefaultLayout() { auto layouts = ContentRegistry::Interface::getLayouts(); if (!layouts.empty()) { @@ -153,9 +214,9 @@ namespace hex::plugin::builtin { ImGui::UnderlinedText("hex.builtin.welcome.start.recent"_lang); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled); { - for (auto &path : s_recentFilePaths) { - if (ImGui::BulletHyperlink(std::fs::path(path).filename().string().c_str())) { - EventManager::post(path); + for (const auto &recentProvider : s_recentProviders) { + if (ImGui::BulletHyperlink(recentProvider.displayName.c_str())) { + loadRecentProvider(recentProvider); break; } } @@ -314,6 +375,8 @@ namespace hex::plugin::builtin { } void createWelcomeScreen() { + updateRecentProviders(); + (void)EventManager::subscribe(drawWelcomeScreen); (void)EventManager::subscribe(drawNoViewsBackground); @@ -405,35 +468,16 @@ namespace hex::plugin::builtin { } }); - (void)EventManager::subscribe([](const auto &path) { - s_recentFilePaths.push_front(path); - + (void)EventManager::subscribe([](prv::Provider *provider) { { - std::list uniques; - for (auto &file : s_recentFilePaths) { + auto recentPath = fs::getDefaultPaths(fs::ImHexPath::Recent).front(); + auto fileName = hex::format("{:%y%m%d_%H%M%S}.json", fmt::gmtime(std::chrono::system_clock::now())); + fs::File recentFile(recentPath / fileName, fs::File::Mode::Create); - bool exists = false; - for (auto &unique : uniques) { - if (file == unique) - exists = true; - } - - if (!exists && !file.empty()) - uniques.push_back(file); - - if (uniques.size() > 5) - break; - } - s_recentFilePaths = uniques; + recentFile.write(provider->storeSettings().dump(4)); } - { - std::vector recentFilesVector; - for (const auto &recentPath : s_recentFilePaths) - recentFilesVector.push_back(recentPath.string()); - - ContentRegistry::Settings::write("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files", recentFilesVector); - } + updateRecentProviders(); }); EventManager::subscribe([](auto) { @@ -442,23 +486,23 @@ namespace hex::plugin::builtin { }); ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1075, [&] { - if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentFilePaths.empty())) { + if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentProviders.empty())) { // Copy to avoid changing list while iteration - std::list recentFilePaths = s_recentFilePaths; - for (auto &path : recentFilePaths) { - auto filename = std::fs::path(path).filename().string(); - if (ImGui::MenuItem(filename.c_str())) { - EventManager::post(path); + auto recentProviders = s_recentProviders; + for (auto &recentProvider : recentProviders) { + if (ImGui::MenuItem(recentProvider.displayName.c_str())) { + loadRecentProvider(recentProvider); } } ImGui::Separator(); if (ImGui::MenuItem("hex.builtin.menu.file.clear_recent"_lang)) { - s_recentFilePaths.clear(); - ContentRegistry::Settings::write( - "hex.builtin.setting.imhex", - "hex.builtin.setting.imhex.recent_files", - std::vector {}); + s_recentProviders.clear(); + + // Remove all recent files + for (const auto &recentPath : fs::getDefaultPaths(fs::ImHexPath::Recent)) + for (const auto &entry : std::fs::directory_iterator(recentPath)) + std::fs::remove(entry.path()); } ImGui::EndMenu(); @@ -474,12 +518,6 @@ namespace hex::plugin::builtin { } } - for (const auto &pathString : ContentRegistry::Settings::read("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files")) { - std::fs::path path = std::u8string(pathString.begin(), pathString.end()); - if (fs::exists(path)) - s_recentFilePaths.emplace_back(path); - } - if (ImHexApi::System::getInitArguments().contains("tip-of-the-day")) { s_tipOfTheDay = ImHexApi::System::getInitArguments()["tip-of-the-day"];