refactor: add a dialog for choosing export encoding
This commit is contained in:
255
materializer/ExportDialog.cpp
Normal file
255
materializer/ExportDialog.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
#if defined(MATERIALIZER_PLUGIN)
|
||||
|
||||
#include "ExportDialog.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace VSW::Materializer {
|
||||
|
||||
class ExportDialogSetting {
|
||||
public:
|
||||
static ExportDialogSetting& GetSingleton();
|
||||
private:
|
||||
static YYCC::yycc_u8string GetConfigFilePath();
|
||||
ExportDialogSetting() :
|
||||
m_LastFilePath(YYCC_U8("last-file-path"), YYCC_U8("")),
|
||||
m_Encoding(YYCC_U8("encoding"), CP_ACP),
|
||||
m_Mgr(ExportDialogSetting::GetConfigFilePath(), UINT64_C(0), {
|
||||
&m_LastFilePath, &m_Encoding
|
||||
}) {
|
||||
m_Mgr.Load();
|
||||
}
|
||||
~ExportDialogSetting() {
|
||||
m_Mgr.Save();
|
||||
}
|
||||
|
||||
public:
|
||||
YYCC::ConfigManager::StringSetting m_LastFilePath;
|
||||
YYCC::ConfigManager::NumberSetting<UINT> m_Encoding;
|
||||
YYCC::ConfigManager::CoreManager m_Mgr;
|
||||
};
|
||||
ExportDialogSetting& ExportDialogSetting::GetSingleton() {
|
||||
static ExportDialogSetting g_Singleton;
|
||||
return g_Singleton;
|
||||
}
|
||||
YYCC::yycc_u8string ExportDialogSetting::GetConfigFilePath() {
|
||||
// get path to executable virtools
|
||||
YYCC::yycc_u8string u8_virtools_path;
|
||||
if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_virtools_path))
|
||||
u8_virtools_path.clear();
|
||||
// get its parent folder and append with cfg file name
|
||||
std::filesystem::path virtools_path(YYCC::FsPathPatch::FromUTF8Path(u8_virtools_path.c_str()));
|
||||
return YYCC::FsPathPatch::ToUTF8Path(virtools_path.parent_path() / YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("vsw_materializer.cfg")));
|
||||
}
|
||||
|
||||
namespace ExportDialogHelper {
|
||||
|
||||
#define RADIOBTN_GETCHECK(instance) (instance.GetCheck() == BST_CHECKED)
|
||||
#define RADIOBTN_SETCHECK(instance, stmt) (instance.SetCheck((stmt) ? BST_CHECKED : BST_UNCHECKED))
|
||||
|
||||
static bool ValidateCodePage(UINT code_page) {
|
||||
CPINFOEXW cpinfo;
|
||||
return GetCPInfoExW(code_page, 0, &cpinfo);
|
||||
}
|
||||
|
||||
static void SetCWndText(CWnd* ctl, const YYCC::yycc_u8string_view& val) {
|
||||
ctl->SetWindowTextA(YYCC::EncodingHelper::UTF8ToChar(val, CP_ACP).c_str());
|
||||
}
|
||||
|
||||
YYCC::yycc_u8string GetCWndText(CWnd* ctl) {
|
||||
// Ref: https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cwnd-class?view=msvc-170#getwindowtext
|
||||
CString recv;
|
||||
ctl->GetWindowTextA(recv);
|
||||
return YYCC::EncodingHelper::CharToUTF8((LPCSTR)recv, CP_ACP);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ExportDialog dialog
|
||||
|
||||
IMPLEMENT_DYNAMIC(ExportDialog, CDialogEx)
|
||||
|
||||
ExportDialog::ExportDialog(CWnd* pParent /*=nullptr*/)
|
||||
: CDialogEx(IDD_EXPORT_DIALOG, pParent),
|
||||
m_InitialDatabaseType(InitialDatabaseType::Script),
|
||||
m_DatabaseFileCache(),
|
||||
m_DatabaseFileResult(), m_EncodingResult(CP_ACP) {}
|
||||
|
||||
ExportDialog::~ExportDialog() {}
|
||||
|
||||
void ExportDialog::DoDataExchange(CDataExchange* pDX) {
|
||||
CDialogEx::DoDataExchange(pDX);
|
||||
DDX_Control(pDX, IDC_EDIT1, m_DatabaseFile);
|
||||
DDX_Control(pDX, IDC_RADIO1, m_EncodingSystem);
|
||||
DDX_Control(pDX, IDC_RADIO2, m_EncodingCustom);
|
||||
DDX_Control(pDX, IDC_EDIT2, m_EncodingCustom_Value);
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(ExportDialog, CDialogEx)
|
||||
// ===== Buttons =====
|
||||
ON_BN_CLICKED(IDOK, &ExportDialog::OnBtnOkClicked)
|
||||
ON_BN_CLICKED(IDCANCEL, &ExportDialog::OnBtnCancelClicked)
|
||||
ON_BN_CLICKED(IDC_BUTTON1, &ExportDialog::OnBtnBrowseClicked)
|
||||
// ===== Radio Buttons =====
|
||||
ON_BN_CLICKED(IDC_RADIO1, &ExportDialog::OnBtnEncodingClicked)
|
||||
ON_BN_CLICKED(IDC_RADIO2, &ExportDialog::OnBtnEncodingClicked)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
#pragma region Initial Settings
|
||||
|
||||
void ExportDialog::SetInitialDatabaseType(InitialDatabaseType db_type) {
|
||||
m_InitialDatabaseType = db_type;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Result Getter
|
||||
|
||||
const YYCC::yycc_u8string& ExportDialog::GetDatabaseFileResult() {
|
||||
return m_DatabaseFileResult;
|
||||
}
|
||||
|
||||
UINT ExportDialog::GetEncodingResult() {
|
||||
return m_EncodingResult;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// ExportDialog message handlers
|
||||
|
||||
#pragma region Event Handler
|
||||
|
||||
BOOL ExportDialog::OnInitDialog() {
|
||||
CDialogEx::OnInitDialog();
|
||||
|
||||
// Read settings from config manager
|
||||
auto& config_manager = ExportDialogSetting::GetSingleton();
|
||||
auto u8_last_path = config_manager.m_LastFilePath.Get();
|
||||
if (!u8_last_path.empty()) {
|
||||
auto last_path = YYCC::FsPathPatch::FromUTF8Path(u8_last_path.c_str());
|
||||
switch (m_InitialDatabaseType) {
|
||||
case InitialDatabaseType::Script:
|
||||
last_path.replace_filename(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("script.db")));
|
||||
break;
|
||||
case InitialDatabaseType::Document:
|
||||
last_path.replace_filename(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("doc.db")));
|
||||
break;
|
||||
case InitialDatabaseType::Environment:
|
||||
last_path.replace_filename(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("env.db")));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("invalid initial database type");
|
||||
}
|
||||
u8_last_path = YYCC::FsPathPatch::ToUTF8Path(last_path);
|
||||
}
|
||||
PushDatabaseFile(u8_last_path);
|
||||
PushEncoding(config_manager.m_Encoding.Get());
|
||||
|
||||
return TRUE; // return TRUE unless you set the focus to a control
|
||||
// EXCEPTION: OCX Property Pages should return FALSE
|
||||
}
|
||||
|
||||
void ExportDialog::OnBtnOkClicked() {
|
||||
// ===== Collect input settings =====
|
||||
m_DatabaseFileResult = PullDatabaseFile();
|
||||
m_EncodingResult = PullEncoding();
|
||||
if (m_DatabaseFileResult.empty()) {
|
||||
MessageBoxW(m_hWnd, L"Exported database file should not be empty!", L"Setting Error", MB_OK + MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
if (!ExportDialogHelper::ValidateCodePage(m_EncodingResult)) {
|
||||
MessageBoxW(m_hWnd, L"Invalid encoding!", L"Setting Error", MB_OK + MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// check done. sync settings to config manager
|
||||
auto& config_manager = ExportDialogSetting::GetSingleton();
|
||||
config_manager.m_LastFilePath.Set(m_DatabaseFileResult);
|
||||
config_manager.m_Encoding.Set(m_EncodingResult);
|
||||
|
||||
CDialogEx::OnOK();
|
||||
}
|
||||
|
||||
void ExportDialog::OnBtnCancelClicked() {
|
||||
CDialogEx::OnCancel();
|
||||
}
|
||||
|
||||
void ExportDialog::OnBtnBrowseClicked() {
|
||||
// configure dialog properties
|
||||
YYCC::DialogHelper::FileDialog dialog_settings;
|
||||
auto& dialog_filter = dialog_settings.ConfigreFileTypes();
|
||||
dialog_filter.Add(YYCC_U8("Database File (*.db)"), { YYCC_U8("*.db") });
|
||||
dialog_settings.SetOwner(this->m_hWnd);
|
||||
switch (m_InitialDatabaseType) {
|
||||
case InitialDatabaseType::Script:
|
||||
dialog_settings.SetInitFileName(YYCC_U8("script.db"));
|
||||
break;
|
||||
case InitialDatabaseType::Document:
|
||||
dialog_settings.SetInitFileName(YYCC_U8("doc.db"));
|
||||
break;
|
||||
case InitialDatabaseType::Environment:
|
||||
dialog_settings.SetInitFileName(YYCC_U8("env.db"));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("invalid initial database type");
|
||||
}
|
||||
|
||||
// open directory picker and assign it if user click ok.
|
||||
YYCC::yycc_u8string picked_file;
|
||||
if (YYCC::DialogHelper::SaveFileDialog(dialog_settings, picked_file)) {
|
||||
PushDatabaseFile(picked_file);
|
||||
}
|
||||
}
|
||||
|
||||
void ExportDialog::OnBtnEncodingClicked() {
|
||||
UpdateLayouts();
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Assist Functions
|
||||
|
||||
const YYCC::yycc_u8string& ExportDialog::PullDatabaseFile() {
|
||||
return m_DatabaseFileCache;
|
||||
}
|
||||
|
||||
void ExportDialog::PushDatabaseFile(const YYCC::yycc_u8string& data) {
|
||||
m_DatabaseFileCache = data;
|
||||
ExportDialogHelper::SetCWndText(&m_DatabaseFile, data);
|
||||
}
|
||||
|
||||
UINT ExportDialog::PullEncoding() {
|
||||
if (RADIOBTN_GETCHECK(m_EncodingSystem)) return CP_ACP;
|
||||
else if (RADIOBTN_GETCHECK(m_EncodingCustom)) {
|
||||
UINT result;
|
||||
if (!YYCC::ParserHelper::TryParse(ExportDialogHelper::GetCWndText(&m_EncodingCustom_Value), result))
|
||||
result = static_cast<UINT>(-1);
|
||||
return result;
|
||||
} else {
|
||||
throw std::runtime_error("invalid encoding selection");
|
||||
}
|
||||
}
|
||||
|
||||
void ExportDialog::PushEncoding(UINT data) {
|
||||
RADIOBTN_SETCHECK(m_EncodingSystem, false);
|
||||
RADIOBTN_SETCHECK(m_EncodingCustom, false);
|
||||
|
||||
if (data == CP_ACP) RADIOBTN_SETCHECK(m_EncodingSystem, true);
|
||||
else {
|
||||
RADIOBTN_SETCHECK(m_EncodingCustom, true);
|
||||
ExportDialogHelper::SetCWndText(&m_EncodingCustom_Value, YYCC::ParserHelper::ToString(data));
|
||||
}
|
||||
|
||||
UpdateLayouts();
|
||||
}
|
||||
|
||||
void ExportDialog::UpdateLayouts() {
|
||||
// enable custom encoding input box according to selection.
|
||||
m_EncodingCustom_Value.EnableWindow(RADIOBTN_GETCHECK(m_EncodingCustom));
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user