1
0
mirror of synced 2024-11-24 15:50:16 +01:00

feat: Allow recents to also display other providers

This commit is contained in:
WerWolv 2022-08-14 10:07:45 +02:00
parent 440ba3823e
commit 85f0e04d0e
14 changed files with 150 additions and 78 deletions

View File

@ -337,12 +337,12 @@ namespace hex {
void add(bool addToList = true) { void add(bool addToList = true) {
auto typeName = T().getTypeName(); auto typeName = T().getTypeName();
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = typeName](const std::string &name, hex::prv::Provider **provider) { (void)EventManager::subscribe<RequestCreateProvider>([expectedName = typeName](const std::string &name, bool skipLoadInterface, hex::prv::Provider **provider) {
if (name != expectedName) return; 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) if (provider != nullptr)
*provider = newProvider; *provider = newProvider;

View File

@ -129,7 +129,7 @@ namespace hex {
EVENT_DEF(RequestOpenFile, std::fs::path); EVENT_DEF(RequestOpenFile, std::fs::path);
EVENT_DEF(RequestChangeTheme, u32); EVENT_DEF(RequestChangeTheme, u32);
EVENT_DEF(RequestOpenPopup, std::string); 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(RequestShowInfoPopup, std::string);
EVENT_DEF(RequestShowErrorPopup, std::string); EVENT_DEF(RequestShowErrorPopup, std::string);

View File

@ -137,7 +137,7 @@ namespace hex {
void resetDirty(); void resetDirty();
bool isDirty(); bool isDirty();
void add(prv::Provider *provider); void add(prv::Provider *provider, bool skipLoadInterface = false);
template<std::derived_from<prv::Provider> T> template<std::derived_from<prv::Provider> T>
void add(auto &&...args) { void add(auto &&...args) {
@ -146,7 +146,7 @@ namespace hex {
void remove(prv::Provider *provider, bool noQuestions = false); 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);
} }

View File

@ -96,7 +96,8 @@ namespace hex::fs {
Resources, Resources,
Constants, Constants,
Encodings, Encodings,
Logs Logs,
Recent
}; };
std::optional<std::fs::path> getExecutablePath(); std::optional<std::fs::path> getExecutablePath();

View File

@ -104,6 +104,9 @@ namespace hex::prv {
virtual std::pair<Region, bool> getRegionValidity(u64 address) const; virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
void skipLoadInterface() { this->m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
protected: protected:
u32 m_currPage = 0; u32 m_currPage = 0;
u64 m_baseAddress = 0; u64 m_baseAddress = 0;
@ -115,6 +118,7 @@ namespace hex::prv {
u32 m_id; u32 m_id;
bool m_dirty = false; bool m_dirty = false;
bool m_skipLoadInterface = false;
private: private:
static u32 s_idCounter; static u32 s_idCounter;

View File

@ -268,10 +268,13 @@ namespace hex {
}); });
} }
void add(prv::Provider *provider) { void add(prv::Provider *provider, bool skipLoadInterface) {
if (Task::getRunningTaskCount() > 0) if (Task::getRunningTaskCount() > 0)
return; return;
if (skipLoadInterface)
provider->skipLoadInterface();
s_providers.push_back(provider); s_providers.push_back(provider);
EventManager::post<EventProviderCreated>(provider); EventManager::post<EventProviderCreated>(provider);
@ -310,9 +313,9 @@ namespace hex {
delete provider; delete provider;
} }
prv::Provider* createProvider(const std::string &unlocalizedName) { prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface) {
prv::Provider* result = nullptr; prv::Provider* result = nullptr;
EventManager::post<RequestCreateProvider>(unlocalizedName, &result); EventManager::post<RequestCreateProvider>(unlocalizedName, skipLoadInterface, &result);
return result; return result;
} }

View File

@ -232,6 +232,9 @@ namespace hex::fs {
case ImHexPath::Yara: case ImHexPath::Yara:
result = appendPath(getDataPaths(), "yara"); result = appendPath(getDataPaths(), "yara");
break; break;
case ImHexPath::Recent:
result = appendPath(getConfigPaths(), "recent");
break;
} }
if (!listNonExisting) { if (!listNonExisting) {

View File

@ -251,6 +251,9 @@ namespace hex::prv {
} }
nlohmann::json Provider::storeSettings(nlohmann::json settings) const { nlohmann::json Provider::storeSettings(nlohmann::json settings) const {
settings["displayName"] = this->getName();
settings["type"] = this->getTypeName();
settings["baseAddress"] = this->m_baseAddress; settings["baseAddress"] = this->m_baseAddress;
settings["currPage"] = this->m_currPage; settings["currPage"] = this->m_currPage;
@ -263,7 +266,7 @@ namespace hex::prv {
} }
std::pair<Region, bool> Provider::getRegionValidity(u64 address) const { std::pair<Region, bool> Provider::getRegionValidity(u64 address) const {
if (address > this->getActualSize()) if (address < this->getActualSize())
return { Region::Invalid(), false }; return { Region::Invalid(), false };
bool insideValidRegion = false; bool insideValidRegion = false;

View File

@ -59,18 +59,20 @@ namespace hex::init {
bool createDirectories() { bool createDirectories() {
bool result = true; bool result = true;
using enum fs::ImHexPath;
constexpr std::array paths = { constexpr std::array paths = {
fs::ImHexPath::Patterns, Patterns,
fs::ImHexPath::PatternsInclude, PatternsInclude,
fs::ImHexPath::Magic, Magic,
fs::ImHexPath::Plugins, Plugins,
fs::ImHexPath::Resources, Resources,
fs::ImHexPath::Config, Config,
fs::ImHexPath::Constants, Constants,
fs::ImHexPath::Yara, Yara,
fs::ImHexPath::Encodings, Encodings,
fs::ImHexPath::Python, Python,
fs::ImHexPath::Logs Logs,
Recent
}; };
// Check if ImHex is installed in portable mode // Check if ImHex is installed in portable mode

View File

@ -27,8 +27,8 @@ namespace hex::plugin::builtin::prv {
[[nodiscard]] std::string getName() const override; [[nodiscard]] std::string getName() const override;
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override { return { }; } [[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override { return { }; }
void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); } void loadSettings(const nlohmann::json &settings) override;
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; } [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
[[nodiscard]] std::string getTypeName() const override { [[nodiscard]] std::string getTypeName() const override {
return "hex.builtin.provider.intel_hex"; return "hex.builtin.provider.intel_hex";

View File

@ -13,11 +13,16 @@
#include "provider_extra_data.hpp" #include "provider_extra_data.hpp"
#include "content/providers/file_provider.hpp"
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
static void openFile(const std::fs::path &path) { static void openFile(const std::fs::path &path) {
ImHexApi::Provider::createProvider("hex.builtin.provider.file"); auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
EventManager::post<EventFileLoaded>(path); if (auto *fileProvider = dynamic_cast<prv::FileProvider*>(provider); fileProvider != nullptr) {
fileProvider->setPath(path);
(void)fileProvider->open();
}
} }
void registerEventHandlers() { void registerEventHandlers() {
@ -77,6 +82,9 @@ namespace hex::plugin::builtin {
}); });
EventManager::subscribe<EventProviderCreated>([](hex::prv::Provider *provider) { EventManager::subscribe<EventProviderCreated>([](hex::prv::Provider *provider) {
if (provider->shouldSkipLoadInterface())
return;
if (provider->hasFilePicker()) { if (provider->hasFilePicker()) {
if (!provider->handleFilePicker()) { if (!provider->handleFilePicker()) {
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
@ -95,9 +103,6 @@ namespace hex::plugin::builtin {
View::showErrorPopup("hex.builtin.popup.error.open"_lang); View::showErrorPopup("hex.builtin.popup.error.open"_lang);
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
} }
if (!provider->isWritable())
View::showErrorPopup("hex.builtin.popup.error.read_only"_lang);
} }
}); });

View File

@ -232,4 +232,16 @@ namespace hex::plugin::builtin::prv {
return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true }; 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<std::string>();
}
nlohmann::json IntelHexProvider::storeSettings(nlohmann::json settings) const {
settings["path"] = this->m_sourceFilePath.string();
return Provider::storeSettings(settings);
}
} }

View File

@ -35,8 +35,9 @@ namespace hex::plugin::builtin {
ImGui::Separator(); ImGui::Separator();
if (ImGui::Button("hex.builtin.common.open"_lang)) { if (ImGui::Button("hex.builtin.common.open"_lang)) {
if (provider->open()) if (provider->open()) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
}
else { else {
View::showErrorPopup("hex.builtin.view.provider_settings.load_error"_lang); View::showErrorPopup("hex.builtin.view.provider_settings.load_error"_lang);
ImHexApi::Provider::remove(provider); ImHexApi::Provider::remove(provider);

View File

@ -6,18 +6,17 @@
#include <hex/ui/view.hpp> #include <hex/ui/view.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
#include <hex/api/project_file_manager.hpp> #include <hex/api/project_file_manager.hpp>
#include <imgui.h> #include <imgui.h>
#include <implot.h> #include <implot.h>
#include <imnodes.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <romfs/romfs.hpp> #include <romfs/romfs.hpp>
#include <fonts/fontawesome_font.h>
#include <fonts/codicons_font.h> #include <fonts/codicons_font.h>
#include <list> #include <list>
@ -25,12 +24,74 @@
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
static ImGui::Texture s_bannerTexture, s_backdropTexture; static ImGui::Texture s_bannerTexture, s_backdropTexture;
static std::list<std::fs::path> s_recentFilePaths;
static std::fs::path s_safetyBackupPath; static std::fs::path s_safetyBackupPath;
static std::string s_tipOfTheDay; 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<RecentProvider> s_recentProviders;
static void updateRecentProviders() {
s_recentProviders.clear();
// Query all recent providers
std::vector<std::fs::path> 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() { static void loadDefaultLayout() {
auto layouts = ContentRegistry::Interface::getLayouts(); auto layouts = ContentRegistry::Interface::getLayouts();
if (!layouts.empty()) { if (!layouts.empty()) {
@ -153,9 +214,9 @@ namespace hex::plugin::builtin {
ImGui::UnderlinedText("hex.builtin.welcome.start.recent"_lang); ImGui::UnderlinedText("hex.builtin.welcome.start.recent"_lang);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled);
{ {
for (auto &path : s_recentFilePaths) { for (const auto &recentProvider : s_recentProviders) {
if (ImGui::BulletHyperlink(std::fs::path(path).filename().string().c_str())) { if (ImGui::BulletHyperlink(recentProvider.displayName.c_str())) {
EventManager::post<RequestOpenFile>(path); loadRecentProvider(recentProvider);
break; break;
} }
} }
@ -314,6 +375,8 @@ namespace hex::plugin::builtin {
} }
void createWelcomeScreen() { void createWelcomeScreen() {
updateRecentProviders();
(void)EventManager::subscribe<EventFrameBegin>(drawWelcomeScreen); (void)EventManager::subscribe<EventFrameBegin>(drawWelcomeScreen);
(void)EventManager::subscribe<EventFrameBegin>(drawNoViewsBackground); (void)EventManager::subscribe<EventFrameBegin>(drawNoViewsBackground);
@ -405,35 +468,16 @@ namespace hex::plugin::builtin {
} }
}); });
(void)EventManager::subscribe<EventFileLoaded>([](const auto &path) { (void)EventManager::subscribe<EventProviderOpened>([](prv::Provider *provider) {
s_recentFilePaths.push_front(path);
{ {
std::list<std::fs::path> uniques; auto recentPath = fs::getDefaultPaths(fs::ImHexPath::Recent).front();
for (auto &file : s_recentFilePaths) { 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; recentFile.write(provider->storeSettings().dump(4));
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;
} }
{ updateRecentProviders();
std::vector<std::string> 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);
}
}); });
EventManager::subscribe<EventProviderCreated>([](auto) { EventManager::subscribe<EventProviderCreated>([](auto) {
@ -442,23 +486,23 @@ namespace hex::plugin::builtin {
}); });
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1075, [&] { 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 // Copy to avoid changing list while iteration
std::list<std::fs::path> recentFilePaths = s_recentFilePaths; auto recentProviders = s_recentProviders;
for (auto &path : recentFilePaths) { for (auto &recentProvider : recentProviders) {
auto filename = std::fs::path(path).filename().string(); if (ImGui::MenuItem(recentProvider.displayName.c_str())) {
if (ImGui::MenuItem(filename.c_str())) { loadRecentProvider(recentProvider);
EventManager::post<RequestOpenFile>(path);
} }
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("hex.builtin.menu.file.clear_recent"_lang)) { if (ImGui::MenuItem("hex.builtin.menu.file.clear_recent"_lang)) {
s_recentFilePaths.clear(); s_recentProviders.clear();
ContentRegistry::Settings::write(
"hex.builtin.setting.imhex", // Remove all recent files
"hex.builtin.setting.imhex.recent_files", for (const auto &recentPath : fs::getDefaultPaths(fs::ImHexPath::Recent))
std::vector<std::string> {}); for (const auto &entry : std::fs::directory_iterator(recentPath))
std::fs::remove(entry.path());
} }
ImGui::EndMenu(); 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")) { if (ImHexApi::System::getInitArguments().contains("tip-of-the-day")) {
s_tipOfTheDay = ImHexApi::System::getInitArguments()["tip-of-the-day"]; s_tipOfTheDay = ImHexApi::System::getInitArguments()["tip-of-the-day"];