From e1c9e02f8167bd6e747e93500f227631adbc80b4 Mon Sep 17 00:00:00 2001 From: matyalatte Date: Sun, 8 May 2022 23:38:54 +0900 Subject: [PATCH 1/5] separete functions related to json --- CMakeLists.txt | 4 +- src/Component.cpp | 29 +++--- src/Component.h | 3 +- src/Exec.cpp | 14 +-- src/Exec.h | 2 +- src/JsonUtils.cpp | 166 ++++++++++++++++++++++++++++++++++ src/JsonUtils.h | 15 ++++ src/MainFrame.cpp | 223 +++++----------------------------------------- src/MainFrame.h | 4 +- 9 files changed, 229 insertions(+), 231 deletions(-) create mode 100644 src/JsonUtils.cpp create mode 100644 src/JsonUtils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 74d513e..417b831 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,10 @@ add_executable(${PROJECT_NAME} "src/MainFrame.cpp" "src/Exec.h" "src/Exec.cpp" - "src/Component.cpp" "src/Component.h" + "src/Component.cpp" + "src/JsonUtils.h" + "src/JsonUtils.cpp" ) #link libraries diff --git a/src/Component.cpp b/src/Component.cpp index 0b2cfd5..a4dd966 100644 --- a/src/Component.cpp +++ b/src/Component.cpp @@ -174,29 +174,29 @@ void Component::SetConfig(nlohmann::json config) { std::vector checks; switch (type) { case comp_type::TYPE_FILE: - if (hasKey(config, "str") && config["str"].is_string()) { + if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { ((wxFilePickerCtrl*)widget)->SetPath(wxString::FromUTF8(config["str"])); ((wxFilePickerCtrl*)widget)->SetInitialDirectory(wxPathOnly(wxString::FromUTF8(config["str"]))); } break; case comp_type::TYPE_FOLDER: - if (hasKey(config, "str") && config["str"].is_string()) { + if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { ((wxDirPickerCtrl*)widget)->SetPath(wxString::FromUTF8(config["str"])); ((wxDirPickerCtrl*)widget)->SetInitialDirectory(wxString::FromUTF8(config["str"])); } break; case comp_type::TYPE_CHOICE: - if (hasKey(config, "int") && config["int"].is_number() && config["int"] < values.size()) { + if (jsonUtils::hasKey(config, "int") && config["int"].is_number() && config["int"] < values.size()) { ((wxChoice*)widget)->SetSelection(config["int"]); } break; case comp_type::TYPE_CHECK: - if (hasKey(config, "int") && config["int"].is_number()) { + if (jsonUtils::hasKey(config, "int") && config["int"].is_number()) { ((wxCheckBox*)widget)->SetValue(config["int"]!=0); } break; case comp_type::TYPE_CHECKS: - if (hasKey(config, "ints") && config["int"].is_array()) { + if (jsonUtils::hasKey(config, "ints") && config["int"].is_array()) { checks = *(std::vector*)widget; for (int i = 0; i < config["ints"].size() && iSetValue(config["ints"][i] != 0); @@ -244,7 +244,7 @@ Component* Component::PutText(wxPanel* panel, nlohmann::json j, int y) { Component* Component::PutFilePicker(wxPanel* panel, nlohmann::json j, int y) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); wxString ext; - if (hasKey(j, "extension")) { + if (jsonUtils::hasKey(j, "extension")) { ext = wxString::FromUTF8(j["extension"]); } else{ @@ -275,18 +275,18 @@ Component* Component::PutChoice(wxPanel* panel, nlohmann::json j, int y) { }); wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); int width = 95; - if (hasKey(j, "width")) { + if (jsonUtils::hasKey(j, "width")) { width = j["width"]; } wxChoice* choice = new wxChoice(panel, wxID_ANY, wxPoint(20, y + 20), wxSize(width, 30), wxitems); - if (hasKey(j, "default") && j["items"].size()>j["default"]) { + if (jsonUtils::hasKey(j, "default") && j["items"].size()>j["default"]) { choice->SetSelection(j["default"]); } else { choice->SetSelection(0); } Component* comp = new Component(choice, comp_type::TYPE_CHOICE); - if (hasKey(j, "values") && j["values"].size() == j["items"].size()) { + if (jsonUtils::hasKey(j, "values") && j["values"].size() == j["items"].size()) { comp->SetValues(j["values"]); } else { @@ -299,7 +299,7 @@ Component* Component::PutChoice(wxPanel* panel, nlohmann::json j, int y) { Component* Component::PutCheckBox(wxPanel* panel, nlohmann::json j, int y) { wxCheckBox* check = new wxCheckBox(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y), wxSize(350, 25)); Component* comp = new Component(check, comp_type::TYPE_CHECK); - if (hasKey(j, "value")) { + if (jsonUtils::hasKey(j, "value")) { comp->SetValue(j["value"]); } else { @@ -319,7 +319,7 @@ Component* Component::PutCheckBoxes(wxPanel* panel, nlohmann::json j, int y) { checks->push_back(check); } Component* comp = new Component(checks, comp_type::TYPE_CHECKS); - if (hasKey(j, "values")) { + if (jsonUtils::hasKey(j, "values")) { comp->SetValues(j["values"]); } else { @@ -354,14 +354,9 @@ Component* Component::PutComponent(wxPanel* panel, nlohmann::json j, int y) { else { std::cout << "[UpdatePanel] unknown component type detected. (" << j["type"] << ")" << std::endl; } - if (hasKey(j, "add_quotes")) { + if (jsonUtils::hasKey(j, "add_quotes")) { comp->SetAddQuotes(j["add_quotes"]); } comp->SetLabel(j["label"]); return comp; } - -bool hasKey(nlohmann::json json, std::string key) { - auto subjectIdIter = json.find(key); - return subjectIdIter != json.end(); -} \ No newline at end of file diff --git a/src/Component.h b/src/Component.h index 637aadd..0bc33f4 100644 --- a/src/Component.h +++ b/src/Component.h @@ -4,6 +4,7 @@ #include #include #include +#include "JsonUtils.h" #ifdef _WIN32 #include //char code converter for Windows system @@ -78,5 +79,3 @@ class Component { std::string wstring_to_utf8(const std::wstring& str); std::wstring utf8_to_wstring(const std::string& str); #endif - -bool hasKey(nlohmann::json json, std::string key); \ No newline at end of file diff --git a/src/Exec.cpp b/src/Exec.cpp index a976fbc..8621da7 100644 --- a/src/Exec.cpp +++ b/src/Exec.cpp @@ -38,7 +38,7 @@ inline bool is_return(const char& input) return input == '\n' || input == '\r'; } -wxString last_line(const wxString& input) +std::string last_line(const std::string& input) { if (input.length() <= 2) return input; size_t position = input.length() - 3; @@ -48,18 +48,18 @@ wxString last_line(const wxString& input) } //get string from stream -wxString read_stream(wxInputStream* stream, char* buf, size_t size) { +std::string read_stream(wxInputStream* stream, char* buf, size_t size) { if (stream->CanRead()) { size_t read_size; stream->Read(buf, size); read_size = stream->LastRead(); - return wxString(buf, read_size); + return std::string(buf, read_size); } return ""; } //run command and return error messages -std::vector exec(const char* cmd) { +std::vector exec(const char* cmd) { //open process wxProcessExecute* process = wxProcessExecute::Open(cmd); @@ -76,9 +76,9 @@ std::vector exec(const char* cmd) { size_t read_size = 0; char ibuf[512]; //buffer for output char ebuf[512]; //buffer for error messages - wxString str = ""; - wxString in_msg = ""; - wxString err_msg = ""; + std::string str = ""; + std::string in_msg = ""; + std::string err_msg = ""; while ((!istream->Eof() && !estream->Eof()) || istream->CanRead() || estream->CanRead()) {//while process is running //print outputs diff --git a/src/Exec.h b/src/Exec.h index 473a406..c82eed2 100644 --- a/src/Exec.h +++ b/src/Exec.h @@ -6,4 +6,4 @@ #include //run command and return error messages -std::vector exec(const char* cmd); \ No newline at end of file +std::vector exec(const char* cmd); \ No newline at end of file diff --git a/src/JsonUtils.cpp b/src/JsonUtils.cpp new file mode 100644 index 0000000..0e2da10 --- /dev/null +++ b/src/JsonUtils.cpp @@ -0,0 +1,166 @@ +#include "JsonUtils.h" + +namespace jsonUtils { + nlohmann::json loadJson(std::string file) { + std::ifstream istream(file); + nlohmann::json json; + if (!istream) { + return nlohmann::json({}); + } + try { + istream >> json; + istream.close(); + } + catch (...) { + json = {}; + } + return json; + } + + bool saveJson(nlohmann::json json, std::string file) { + std::ofstream ostream(file); + + if (!ostream) { + return false; + } + ostream << std::setw(4) << json << std::endl; + ostream.close(); + return true + } + + bool hasKey(nlohmann::json json, std::string key) { + auto subjectIdIter = json.find(key); + return subjectIdIter != json.end(); + } + + //get default definition of gui + nlohmann::json default_definition() { + nlohmann::json def = + { + {"label", "Default GUI"}, + #ifdef _WIN32 + {"command", "dir" }, + {"button", "run 'dir'"}, + #else + {"command", "ls" }, + {"button", "run 'ls'"}, + #endif + {"components",{}} + }; + return def; + } + + std::string checkSubDefinition(nlohmann::json sub_definition) { + //check if keys exist + std::vector keys = { "label", "button", "command", "components" }; + for (std::string key : keys) { + if (!hasKey(sub_definition, key)) { + return "'" + key + "' not found."; + } + } + + //check is_string + keys = { "label", "button", "command" }; + if (hasKey(sub_definition, "window_name")) { + keys.push_back("window_name"); + } + for (std::string key : keys) { + if (!sub_definition[key].is_string()) { + return "'" + key + "' should be a string."; + } + } + + //check is_boolean + if (hasKey(sub_definition, "show_last_line") && !sub_definition["show_last_line"].is_boolean()) { + return "'show_last_line' should be a boolean."; + } + + //check is_array + keys = { "components" }; + for (std::string key : keys) { + if (!sub_definition[key].is_array()) { + return "'" + key + "' should be an array."; + } + } + + //check components + keys = { "type", "label" }; + std::vector subkeys = {}; + std::string label; + for (nlohmann::json c : sub_definition["components"]) { + //check if type and label exist + for (std::string key : keys) { + if (!hasKey(c, key)) { + return "components['" + key + "'] not found."; + } + if (!c[key].is_string()) { + return "components['" + key + "'] should be a string."; + } + } + label = c["label"]; + if (c["type"] == "file") { + if (hasKey(c, "extention") && !c["extension"].is_string()) { + return label + "['extention'] should be a string."; + } + } + else if (c["type"] == "choice") { + subkeys = { "items", "values" }; + for (std::string key : subkeys) { + if (hasKey(c, key) && !c[key].is_array()) { + return label + "['" + key + "'] should be an array."; + } + } + subkeys = { "width", "default" }; + for (std::string key : subkeys) { + if (hasKey(c, key) && !c[key].is_number()) { + return label + "['" + key + "'] should be an int."; + } + } + } + else if (c["type"] == "check") { + if (hasKey(c, "value") && !c["value"].is_string()) { + return label + "['value'] should be a string."; + } + } + else if (c["type"] == "checks") { + if (!hasKey(c, "items")) { + return label + "['items'] not found."; + } + if (!c["items"].is_array()) { + return label + "['items'] should be an array."; + } + if (hasKey(c, "values")) { + if (!c["values"].is_array()) { + return label + "['values'] should be an array."; + } + if (c["values"].size() != c["items"].size()) { + return label + "['values'] and " + label + "['items'] should have the same size."; + } + } + } + if (hasKey(c, "add_quotes") && !c["add_quotes"].is_boolean()) { + return label + "['add_quotes'] should be a boolean."; + } + } + return "__null__"; + } + + std::string checkHelpURLs(nlohmann::json definition) { + if (!definition["help"].is_array()) { + return "'help' should be an array."; + } + std::vector keys = { "type", "label", "url" }; + for (nlohmann::json h : definition["help"]) { + for (std::string key : keys) { + if (!hasKey(h, key)) { + return "'" + key + "' not found."; + } + if (!h[key].is_string()) { + return "'" + key + "' should be a string."; + } + } + } + return "__null__"; + } + +} diff --git a/src/JsonUtils.h b/src/JsonUtils.h new file mode 100644 index 0000000..e41b068 --- /dev/null +++ b/src/JsonUtils.h @@ -0,0 +1,15 @@ +#pragma once +#include +#include +#include + +namespace jsonUtils { + nlohmann::json loadJson(std::string file); + bool saveJson(nlohmann::json json, std::string file); + + bool hasKey(nlohmann::json json, std::string key); + + nlohmann::json default_definition(); + std::string checkSubDefinition(nlohmann::json sub_definition); + std::string checkHelpURLs(nlohmann::json definition); +} \ No newline at end of file diff --git a/src/MainFrame.cpp b/src/MainFrame.cpp index 10d1e45..da8376f 100644 --- a/src/MainFrame.cpp +++ b/src/MainFrame.cpp @@ -51,7 +51,7 @@ MainFrame::MainFrame() //get gui definition LoadDefinition(); - LoadConfig(); + config = jsonUtils::loadJson("gui_config.json"); //make menu bar wxMenuBar* menuBar = new wxMenuBar; @@ -67,7 +67,7 @@ MainFrame::MainFrame() menuBar->Append(menuFile, "Menu"); //put help urls to menu bar - if (hasKey(definition, "help")) { + if (jsonUtils::hasKey(definition, "help")) { wxMenu* menuHelp = new wxMenu; for (int i = 0; i < definition["help"].size(); i++) { @@ -99,189 +99,38 @@ MainFrame::MainFrame() SetWindowStyleFlag(wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER & ~wxMAXIMIZE_BOX); } -//get default definition of gui -nlohmann::json default_definition() { - nlohmann::json def = - { - {"label", "Default GUI"}, -#ifdef _WIN32 - {"command", "dir" }, - {"button", "run 'dir'"}, -#else - {"command", "ls" }, - {"button", "run 'ls'"}, -#endif - {"components",{}} - }; - return def; -} - -/* -bool hasKey(nlohmann::json json, std::string key) { - auto subjectIdIter = json.find(key); - return subjectIdIter != json.end(); -} -*/ - - -std::string checkSubDefinition(nlohmann::json sub_definition) { - //check if keys exist - std::vector keys = { "label", "button", "command", "components" }; - for (std::string key : keys) { - if (!hasKey(sub_definition, key)) { - return "'" + key + "' not found."; - } - } - - //check is_string - keys = { "label", "button", "command"}; - if (hasKey(sub_definition, "window_name")) { - keys.push_back("window_name"); - } - for (std::string key : keys) { - if (!sub_definition[key].is_string()) { - return "'" + key + "' should be a string."; - } - } - - //check is_boolean - if (hasKey(sub_definition, "show_last_line") && !sub_definition["show_last_line"].is_boolean()) { - return "'show_last_line' should be a boolean."; - } - - //check is_array - keys = { "components" }; - for (std::string key : keys) { - if (!sub_definition[key].is_array()) { - return "'" + key + "' should be an array."; - } - } - - //check components - keys = { "type", "label" }; - std::vector subkeys = {}; - std::string label; - for (nlohmann::json c : sub_definition["components"]) { - //check if type and label exist - for (std::string key : keys) { - if (!hasKey(c, key)) { - return "components['" + key + "'] not found."; - } - if (!c[key].is_string()) { - return "components['" + key + "'] should be a string."; - } - } - label = c["label"]; - if (c["type"]=="file"){ - if (hasKey(c, "extention") && !c["extension"].is_string()) { - return label + "['extention'] should be a string."; - } - } - else if(c["type"] == "choice") { - subkeys = { "items", "values" }; - for (std::string key : subkeys) { - if (hasKey(c, key) && !c[key].is_array()) { - return label + "['" + key +"'] should be an array."; - } - } - subkeys = { "width", "default" }; - for (std::string key : subkeys) { - if (hasKey(c, key) && !c[key].is_number()) { - return label + "['" + key + "'] should be an int."; - } - } - } - else if (c["type"] == "check") { - if (hasKey(c, "value") && !c["value"].is_string()) { - return label + "['value'] should be a string."; - } - } - else if (c["type"] == "checks") { - if (!hasKey(c, "items")) { - return label + "['items'] not found."; - } - if (!c["items"].is_array()) { - return label + "['items'] should be an array."; - } - if (hasKey(c, "values")) { - if (!c["values"].is_array()) { - return label + "['values'] should be an array."; - } - if (c["values"].size()!=c["items"].size()) { - return label + "['values'] and " + label + "['items'] should have the same size."; - } - } - } - if (hasKey(c, "add_quotes") && !c["add_quotes"].is_boolean()) { - return label + "['add_quotes'] should be a boolean."; - } - } - return "__null__"; -} - -std::string checkHelpURLs(nlohmann::json definition) { - if (!definition["help"].is_array()) { - return "'help' should be an array."; - } - std::vector keys = { "type", "label", "url" }; - for (nlohmann::json h : definition["help"]) { - for (std::string key : keys) { - if (!hasKey(h, key)) { - return "'" + key + "' not found."; - } - if (!h[key].is_string()) { - return "'" + key + "' should be a string."; - } - } - } - return "__null__"; -} //read gui_definition.json void MainFrame::LoadDefinition() { std::ifstream istream("gui_definition.json"); std::string msg; + definition = jsonUtils::loadJson("gui_definition.json"); - if (!istream) { - msg = "Fialed to load gui_definition.json (Not found)"; + if (definition == nlohmann::json({})) { + msg = "Fialed to load gui_definition.json (Can't read)"; std::cout << "[LoadDefinition] " << msg << std::endl; ShowErrorDialog(msg); - sub_definition = default_definition(); + sub_definition = jsonUtils::default_definition(); definition = { { "gui", {sub_definition}} }; return; } - //read json file - try { - istream >> definition; - istream.close(); - } - catch (...) { - msg = "Fialed to load gui_definition.json (Can not read)"; - std::cout << "[LoadDefinition] " << msg << std::endl; - ShowErrorDialog(msg); - sub_definition = default_definition(); - definition = { { "gui", {sub_definition}} }; - return; - } - - //check format - if (hasKey(definition, "gui") && definition["gui"].is_array()) { + if (jsonUtils::hasKey(definition, "gui") && definition["gui"].is_array()) { sub_definition = definition["gui"][0]; } else { msg = "Fialed to load gui_definition.json ('gui' array not found.)"; std::cout << "[LoadDefinition] " << msg << std::endl; ShowErrorDialog(msg); - sub_definition = default_definition(); + sub_definition = jsonUtils::default_definition(); definition = { { "gui", {sub_definition}} }; return; } //check help urls - if (hasKey(definition, "help")) { - msg = checkHelpURLs(definition); + if (jsonUtils::hasKey(definition, "help")) { + msg = jsonUtils::checkHelpURLs(definition); if (msg != "__null__") { msg = "Fialed to load help URLs (" + msg + ")"; std::cout << "[LoadDefinition] " << msg << std::endl; @@ -291,57 +140,31 @@ void MainFrame::LoadDefinition() { } } - //check panel definitions - msg = checkSubDefinition(sub_definition); + msg = jsonUtils::checkSubDefinition(sub_definition); if (msg!="__null__") { msg = "Fialed to load gui_definition.json ("+ msg +")"; std::cout << "[LoadDefinition] " << msg << std::endl; ShowErrorDialog(msg); - sub_definition = default_definition(); + sub_definition = jsonUtils::default_definition(); return; } std::cout << "[LoadDefinition] Loaded gui_definition.json" << std::endl; } - - void MainFrame::UpdateConfig() { for (Component c: components){ config[c.GetLabel()] = c.GetConfig(); } } -void MainFrame::LoadConfig() { - std::ifstream istream("gui_config.json"); - if (!istream) { - std::cout << "[LoadConfig] Fialed to load gui_config.json" << std::endl; - config = {}; - } - else { - try { - istream >> config; - istream.close(); - std::cout << "[LoadConfig] Loaded gui_config.json" << std::endl; - } - catch(...) { - std::cout << "[LoadConfig] Fialed to load gui_config.json" << std::endl; - config = {}; - } - } - -} void MainFrame::SaveConfig() { - UpdateConfig(); - std::ofstream ostream("gui_config.json"); - - if (!ostream) { - std::cout << "[SaveConfig] Fialed to write gui_config.json" << std::endl; + bool saved = jsonUtils::saveJson(config, "gui_config.json"); + if (saved) { + std::cout << "[SaveConfig] Saved gui_config.json" << std::endl; } else { - std::cout << "[SaveConfig] Saved gui_config.json" << std::endl; - ostream << std::setw(4) << config << std::endl; - ostream.close(); + std::cout << "[SaveConfig] Failed to write gui_config.json" << std::endl; } } @@ -383,6 +206,7 @@ std::vector split(const std::string& s, const char delimiter) //run command void MainFrame::RunCommand(wxCommandEvent& event) { //save config + UpdateConfig(); SaveConfig(); //make command string @@ -412,7 +236,7 @@ void MainFrame::RunCommand(wxCommandEvent& event) { #ifdef _WIN32 cmd = "cmd.exe /c " + cmd; #endif - std::vector msg = exec(cmd); + std::vector msg = exec(cmd); runButton->SetLabel(text); if (msg[0] == "__null__") { std::cout << "[RunCommand] Execution failed. " << std::endl; @@ -424,7 +248,7 @@ void MainFrame::RunCommand(wxCommandEvent& event) { ShowErrorDialog(msg[1]); } else {//if success - if (hasKey(sub_definition, "show_last_line") && sub_definition["show_last_line"]!=0 && msg[0]!="") { + if (jsonUtils::hasKey(sub_definition, "show_last_line") && sub_definition["show_last_line"]!=0 && msg[0]!="") { ShowSuccessDialog(msg[0]); } else { @@ -444,12 +268,12 @@ void MainFrame::OpenURL(wxCommandEvent& event) { void MainFrame::UpdateFrame(wxCommandEvent& event) { sub_definition = definition["gui"][event.GetId() - 1 - wxID_HIGHEST]; - std::string msg = checkSubDefinition(sub_definition); + std::string msg = jsonUtils::checkSubDefinition(sub_definition); if (msg != "__null__") { msg = "Json format error(" + msg + ")"; std::cout << "[UpdateFrame] " << msg << std::endl; ShowErrorDialog(msg); - sub_definition = default_definition(); + sub_definition = jsonUtils::default_definition(); return; } @@ -476,14 +300,13 @@ int MainFrame::UpdatePanel(wxPanel* panel) std::string str = "Simple Command Runner"; str = sub_definition["label"]; std::cout << "[UpdatePanel] " << str.c_str() << std::endl; - if (hasKey(sub_definition, "window_name")) { + if (jsonUtils::hasKey(sub_definition, "window_name")) { SetLabel(wxString::FromUTF8(sub_definition["window_name"])); } else { SetLabel("Simple Command Runner"); } - //file picker int y = 10; if (sub_definition["components"].is_null()) { sub_definition["components"] = std::vector(); @@ -499,7 +322,7 @@ int MainFrame::UpdatePanel(wxPanel* panel) newComp = Component::PutComponent(panel, c, y); if (newComp != nullptr) { y += newComp->GetHeight(); - if (hasKey(config, newComp->GetLabel())) { + if (jsonUtils::hasKey(config, newComp->GetLabel())) { newComp->SetConfig(config[newComp->GetLabel()]); } components.push_back(*newComp); diff --git a/src/MainFrame.h b/src/MainFrame.h index 551cb88..ecff407 100644 --- a/src/MainFrame.h +++ b/src/MainFrame.h @@ -4,8 +4,7 @@ #include #include "Component.h" #include "Exec.h" -#include -#include +#include "JsonUtils.h" #ifndef _WIN32 #include @@ -39,7 +38,6 @@ class MainFrame : public wxFrame void LoadDefinition(); int UpdatePanel(wxPanel* panel); - void LoadConfig(); void UpdateConfig(); void SaveConfig(); void ShowErrorDialog(wxString msg); From 8b1f7fc2c7380cce9e6af34caf90a837237b5a2c Mon Sep 17 00:00:00 2001 From: matyalatte Date: Mon, 9 May 2022 02:10:46 +0900 Subject: [PATCH 2/5] use polymorphic class for GUI components --- src/Component.cpp | 390 ++++++++++++++++++++-------------------------- src/Component.h | 83 ++++++---- src/JsonUtils.cpp | 2 +- src/MainFrame.cpp | 14 +- src/MainFrame.h | 2 +- 5 files changed, 235 insertions(+), 256 deletions(-) diff --git a/src/Component.cpp b/src/Component.cpp index a4dd966..55c7e9f 100644 --- a/src/Component.cpp +++ b/src/Component.cpp @@ -17,106 +17,26 @@ bool DropFilePath::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fil } //Component for GUI -Component::Component(void* wid, int t) { - widget = wid; - type = t; - height = 0; - switch (t){ - case comp_type::TYPE_TEXT: - hasString = false; - break; - default: - hasString = true; +Component::Component(nlohmann::json j, int height, bool hasString) { + widget = nullptr; + this->height = height; + this->hasString = hasString; + label = j["label"]; + addQuotes = false; + if (jsonUtils::hasKey(j, "add_quotes")) { + addQuotes= j["add_quotes"]; } } Component::~Component() { - //delete this->widget; }; void Component::SetValues(std::vector vals) { values = vals; } -void Component::SetValue(std::string val) { - value = val; -} - -int Component::GetInt() { - int i=0; - switch (type) { - case comp_type::TYPE_FILE: - case comp_type::TYPE_FOLDER: - i = 0; - break; - case comp_type::TYPE_CHOICE: - i = ((wxChoice*)widget)->GetSelection(); - break; - case comp_type::TYPE_CHECK: - i = (int)((wxCheckBox*)widget)->IsChecked(); - break; - default: - i = 0; - } - return i; -} - -std::vector Component::GetInts() { - std::vector ints; - switch (type) { - case comp_type::TYPE_FILE: - case comp_type::TYPE_FOLDER: - break; - case comp_type::TYPE_CHOICE: - ints.push_back(((wxChoice*)widget)->GetSelection()); - break; - case comp_type::TYPE_CHECK: - ints.push_back((int)((wxCheckBox*)widget)->IsChecked()); - break; - case comp_type::TYPE_CHECKS: - for (wxCheckBox* check: *(std::vector*)widget) { - ints.push_back(check->GetValue()); - } - break; - default: - break; - } - return ints; -} - wxString Component::GetRawString() { - wxString str = ""; - std::vector checks; - int sel; - switch (type) { - case comp_type::TYPE_FILE: - str = ((wxFilePickerCtrl*)widget)->GetPath(); - break; - case comp_type::TYPE_FOLDER: - str = ((wxDirPickerCtrl*)widget)->GetPath(); - break; - case comp_type::TYPE_CHOICE: - sel = ((wxChoice*)widget)->GetSelection(); - str = wxString::FromUTF8(values[sel]); - break; - case comp_type::TYPE_CHECK: - if (((wxCheckBox*)widget)->GetValue()) { - str = wxString::FromUTF8(value); - } - break; - case comp_type::TYPE_CHECKS: - str = ""; - checks = *(std::vector*)widget; - for (int i = 0; i < checks.size(); i++) { - if (checks[i]->GetValue()) { - str += wxString::FromUTF8(values[i]); - } - } - break; - default: - str = ""; - } - return str; + return ""; } wxString Quote(wxString str) { @@ -146,66 +66,10 @@ std::wstring utf8_to_wstring(const std::string& str) #endif nlohmann::json Component::GetConfig() { - nlohmann::json config = {}; - switch (type) { - case comp_type::TYPE_FILE: - case comp_type::TYPE_FOLDER: -#ifdef _WIN32 - //utf-16 to utf-8 for Windows - config["str"] = wstring_to_utf8(std::wstring(GetRawString())); -#else - config["str"] = GetRawString(); -#endif - break; - case comp_type::TYPE_CHOICE: - case comp_type::TYPE_CHECK: - config["int"] = GetInt(); - break; - case comp_type::TYPE_CHECKS: - config["ints"] = GetInts(); - break; - default: - break; - } - return config; + return {}; } void Component::SetConfig(nlohmann::json config) { - std::vector checks; - switch (type) { - case comp_type::TYPE_FILE: - if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { - ((wxFilePickerCtrl*)widget)->SetPath(wxString::FromUTF8(config["str"])); - ((wxFilePickerCtrl*)widget)->SetInitialDirectory(wxPathOnly(wxString::FromUTF8(config["str"]))); - } - break; - case comp_type::TYPE_FOLDER: - if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { - ((wxDirPickerCtrl*)widget)->SetPath(wxString::FromUTF8(config["str"])); - ((wxDirPickerCtrl*)widget)->SetInitialDirectory(wxString::FromUTF8(config["str"])); - } - break; - case comp_type::TYPE_CHOICE: - if (jsonUtils::hasKey(config, "int") && config["int"].is_number() && config["int"] < values.size()) { - ((wxChoice*)widget)->SetSelection(config["int"]); - } - break; - case comp_type::TYPE_CHECK: - if (jsonUtils::hasKey(config, "int") && config["int"].is_number()) { - ((wxCheckBox*)widget)->SetValue(config["int"]!=0); - } - break; - case comp_type::TYPE_CHECKS: - if (jsonUtils::hasKey(config, "ints") && config["int"].is_array()) { - checks = *(std::vector*)widget; - for (int i = 0; i < config["ints"].size() && iSetValue(config["ints"][i] != 0); - } - } - break; - default: - break; - } } void Component::SetHeight(int h) { @@ -214,60 +78,119 @@ void Component::SetHeight(int h) { int Component::GetHeight() { return height; } -int Component::GetType() { - return type; -} - -void Component::SetLabel(std::string str) { - label = str; -} std::string Component::GetLabel() { return label; } -void Component::SetAddQuotes(bool add) { - addQuotes = add; -} - bool Component::HasString() { return hasString; } -Component* Component::PutText(wxPanel* panel, nlohmann::json j, int y) { - wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); - Component* comp = new Component(nullptr, comp_type::TYPE_TEXT); - comp->SetHeight(25); +Component* Component::PutComponent(wxPanel* panel, nlohmann::json j, int y) { + Component* comp=nullptr; + if (j["type"] == "text") {//text + comp = new Text(panel, j, y); + } + else if (j["type"] == "file") {//file picker + comp = new FilePicker(panel, j, y); + } + else if (j["type"] == "folder") {//dir picker + comp = new DirPicker(panel, j, y); + } + else if (j["type"] == "choice") {//choice + comp = new Choice(panel, j, y); + } + else if (j["type"] == "check") {//checkbox + comp = new CheckBox(panel, j, y); + } + else if (j["type"] == "checks") {//checkboxes + comp = new CheckBoxes(panel, j, y); + } + else { + std::cout << "[UpdatePanel] unknown component type detected. (" << j["type"] << ")" << std::endl; + } return comp; } -Component* Component::PutFilePicker(wxPanel* panel, nlohmann::json j, int y) { +const bool HAS_STRING = true; +const bool NOT_STRING = false; + +Text::Text(wxPanel* panel, nlohmann::json j, int y): Component(j, 25, NOT_STRING) { + wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); +} + +//File Picker +FilePicker::FilePicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 50, HAS_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); wxString ext; if (jsonUtils::hasKey(j, "extension")) { ext = wxString::FromUTF8(j["extension"]); } - else{ + else { ext = "any files | *"; } wxFilePickerCtrl* picker = new wxFilePickerCtrl(panel, wxID_ANY, "", "", ext, wxPoint(20, y + 15), wxSize(350, 25), wxFLP_DEFAULT_STYLE | wxFLP_USE_TEXTCTRL); picker->GetTextCtrl()->SetDropTarget(new DropFilePath(picker)); picker->DragAcceptFiles(true); - Component* comp = new Component(picker, comp_type::TYPE_FILE); - comp->SetHeight(50); - return comp; + widget = picker; +} + +wxString FilePicker::GetRawString(){ + return ((wxFilePickerCtrl*)widget)->GetPath(); +} + +void FilePicker::SetConfig(nlohmann::json config){ + if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { + ((wxFilePickerCtrl*)widget)->SetPath(wxString::FromUTF8(config["str"])); + ((wxFilePickerCtrl*)widget)->SetInitialDirectory(wxPathOnly(wxString::FromUTF8(config["str"]))); + } +} + +nlohmann::json FilePicker::GetConfig() { + nlohmann::json config = {}; +#ifdef _WIN32 + //utf-16 to utf-8 for Windows + config["str"] = wstring_to_utf8(std::wstring(GetRawString())); +#else + config["str"] = GetRawString(); +#endif + return config; } -Component* Component::PutDirPicker(wxPanel* panel, nlohmann::json j, int y) { +//Dir Picker +DirPicker::DirPicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 50, HAS_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); wxDirPickerCtrl* picker = new wxDirPickerCtrl(panel, wxID_ANY, "", "", wxPoint(20, y + 15), wxSize(350, 25), wxDIRP_DEFAULT_STYLE | wxDIRP_USE_TEXTCTRL); picker->GetTextCtrl()->SetDropTarget(new DropFilePath(picker)); picker->DragAcceptFiles(true); - Component* comp = new Component(picker, comp_type::TYPE_FOLDER); - comp->SetHeight(50); - return comp; + widget = picker; +} + +wxString DirPicker::GetRawString() { + return ((wxDirPickerCtrl*)widget)->GetPath(); +} + +void DirPicker::SetConfig(nlohmann::json config) { + if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { + ((wxDirPickerCtrl*)widget)->SetPath(wxString::FromUTF8(config["str"])); + ((wxDirPickerCtrl*)widget)->SetInitialDirectory(wxString::FromUTF8(config["str"])); + } +} + +nlohmann::json DirPicker::GetConfig() { + nlohmann::json config = {}; +#ifdef _WIN32 + //utf-16 to utf-8 for Windows + config["str"] = wstring_to_utf8(std::wstring(GetRawString())); +#else + config["str"] = GetRawString(); +#endif + return config; } -Component* Component::PutChoice(wxPanel* panel, nlohmann::json j, int y) { + +//Choice +Choice::Choice(wxPanel* panel, nlohmann::json j, int y) : Component(j, 55, HAS_STRING) { wxArrayString wxitems; std::vector items = j["items"]; std::for_each(items.begin(), items.end(), [&](std::string i) { @@ -279,38 +202,71 @@ Component* Component::PutChoice(wxPanel* panel, nlohmann::json j, int y) { width = j["width"]; } wxChoice* choice = new wxChoice(panel, wxID_ANY, wxPoint(20, y + 20), wxSize(width, 30), wxitems); - if (jsonUtils::hasKey(j, "default") && j["items"].size()>j["default"]) { + if (jsonUtils::hasKey(j, "default") && j["items"].size() > j["default"]) { choice->SetSelection(j["default"]); } else { choice->SetSelection(0); } - Component* comp = new Component(choice, comp_type::TYPE_CHOICE); if (jsonUtils::hasKey(j, "values") && j["values"].size() == j["items"].size()) { - comp->SetValues(j["values"]); + SetValues(j["values"]); } else { - comp->SetValues(j["items"]); + SetValues(j["items"]); } - comp->SetHeight(55); - return comp; + widget = choice; +} + +wxString Choice::GetRawString() { + int sel = ((wxChoice*)widget)->GetSelection(); + return wxString::FromUTF8(values[sel]); } -Component* Component::PutCheckBox(wxPanel* panel, nlohmann::json j, int y) { +void Choice::SetConfig(nlohmann::json config) { + if (jsonUtils::hasKey(config, "int") && config["int"].is_number() && config["int"] < values.size()) { + ((wxChoice*)widget)->SetSelection(config["int"]); + } +} + +nlohmann::json Choice::GetConfig() { + nlohmann::json config = {}; + config["int"] = ((wxChoice*)widget)->GetSelection(); + return config; +} + +//CheckBox +CheckBox::CheckBox(wxPanel* panel, nlohmann::json j, int y) : Component(j, 35, HAS_STRING) { wxCheckBox* check = new wxCheckBox(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y), wxSize(350, 25)); - Component* comp = new Component(check, comp_type::TYPE_CHECK); if (jsonUtils::hasKey(j, "value")) { - comp->SetValue(j["value"]); + value = j["value"]; } else { - comp->SetValue(j["label"]); + value = j["label"]; } - //components->push_back(*comp); - comp->SetHeight(35); - return comp; + widget = check; +} + +wxString CheckBox::GetRawString() { + if (((wxCheckBox*)widget)->GetValue()) { + return wxString::FromUTF8(value); + } + return ""; +} + +void CheckBox::SetConfig(nlohmann::json config) { + if (jsonUtils::hasKey(config, "int") && config["int"].is_number()) { + ((wxCheckBox*)widget)->SetValue(config["int"] != 0); + } +} + +nlohmann::json CheckBox::GetConfig() { + nlohmann::json config = {}; + config["int"] = (int)((wxCheckBox*)widget)->IsChecked(); + return config; } -Component* Component::PutCheckBoxes(wxPanel* panel, nlohmann::json j, int y) { +//CheckBoxes +CheckBoxes::CheckBoxes(wxPanel* panel, nlohmann::json j, int y) : Component(j, 20 + j["items"].size() * 20 + 10, HAS_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); std::vector* checks = new std::vector(); wxCheckBox* check; @@ -318,45 +274,43 @@ Component* Component::PutCheckBoxes(wxPanel* panel, nlohmann::json j, int y) { check = new wxCheckBox(panel, wxID_ANY, wxString::FromUTF8(j["items"][i]), wxPoint(20, y + 20 + i * 20), wxSize(350, 15)); checks->push_back(check); } - Component* comp = new Component(checks, comp_type::TYPE_CHECKS); if (jsonUtils::hasKey(j, "values")) { - comp->SetValues(j["values"]); + SetValues(j["values"]); } else { - comp->SetValues(j["items"]); + SetValues(j["items"]); } - //components->push_back(*comp); - comp->SetHeight(20 + j["items"].size() * 20 + 10); - return comp; + widget = checks; } - -Component* Component::PutComponent(wxPanel* panel, nlohmann::json j, int y) { - Component* comp=nullptr; - if (j["type"] == "text") {//text - comp = Component::PutText(panel, j, y); - } - else if (j["type"] == "file") {//file picker - comp = Component::PutFilePicker(panel, j, y); - } - else if (j["type"] == "folder") {//dir picker - comp = Component::PutDirPicker(panel, j, y); - } - else if (j["type"] == "choice") {//choice - comp = Component::PutChoice(panel, j, y); - } - else if (j["type"] == "check") {//checkbox - comp = Component::PutCheckBox(panel, j, y); - } - else if (j["type"] == "checks") {//checkboxes - comp = Component::PutCheckBoxes(panel, j, y); - } - else { - std::cout << "[UpdatePanel] unknown component type detected. (" << j["type"] << ")" << std::endl; +wxString CheckBoxes::GetRawString() { + wxString str = ""; + std::vector checks; + checks = *(std::vector*)widget; + for (int i = 0; i < checks.size(); i++) { + if (checks[i]->GetValue()) { + str += wxString::FromUTF8(values[i]); + } } - if (jsonUtils::hasKey(j, "add_quotes")) { - comp->SetAddQuotes(j["add_quotes"]); + return str; +} + +void CheckBoxes::SetConfig(nlohmann::json config) { + std::vector checks; + if (jsonUtils::hasKey(config, "ints") && config["int"].is_array()) { + checks = *(std::vector*)widget; + for (int i = 0; i < config["ints"].size() && i < checks.size(); i++) { + checks[i]->SetValue(config["ints"][i] != 0); + } } - comp->SetLabel(j["label"]); - return comp; } + +nlohmann::json CheckBoxes::GetConfig() { + nlohmann::json config = {}; + std::vector ints; + for (wxCheckBox* check : *(std::vector*)widget) { + ints.push_back(check->GetValue()); + } + config["ints"] = ints; + return config; +} \ No newline at end of file diff --git a/src/Component.h b/src/Component.h index 0bc33f4..c31b25b 100644 --- a/src/Component.h +++ b/src/Component.h @@ -24,52 +24,32 @@ class DropFilePath : public wxFileDropTarget virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) override; }; -enum comp_type { - TYPE_TEXT, - TYPE_FILE, - TYPE_FOLDER, - TYPE_CHOICE, - TYPE_CHECK, - TYPE_CHECKS -}; - //component for GUI class Component { -private: +protected: void* widget; - int type; - int height; std::vector values; std::string value; + + +private: + int height; bool hasString; bool addQuotes; std::string label; - wxString GetRawString(); - void SetLabel(std::string str); - void SetAddQuotes(bool add); - - static Component* PutText(wxPanel* panel, nlohmann::json j, int y); - static Component* PutFilePicker(wxPanel* panel, nlohmann::json j, int y); - static Component* PutDirPicker(wxPanel* panel, nlohmann::json j, int y); - static Component* PutChoice(wxPanel* panel, nlohmann::json j, int y); - static Component* PutCheckBox(wxPanel* panel, nlohmann::json j, int y); - static Component* PutCheckBoxes(wxPanel* panel, nlohmann::json j, int y); public: - Component(void* wid, int t); + Component(nlohmann::json j, int height, bool hasString); ~Component(); + virtual wxString GetRawString(); wxString GetString(); std::string GetLabel(); - int GetInt(); - std::vector GetInts(); int GetHeight(); - int GetType(); - nlohmann::json GetConfig(); - void SetConfig(nlohmann::json config); + virtual nlohmann::json GetConfig(); + virtual void SetConfig(nlohmann::json config); void SetHeight(int h); void SetValues(std::vector vals); - void SetValue(std::string val); bool HasString(); static Component* PutComponent(wxPanel* panel, nlohmann::json j, int y); @@ -79,3 +59,48 @@ class Component { std::string wstring_to_utf8(const std::wstring& str); std::wstring utf8_to_wstring(const std::string& str); #endif + +class Text : public Component { +public: + Text(wxPanel* panel, nlohmann::json j, int y); +}; + +class FilePicker : public Component { +public: + wxString GetRawString() override; + FilePicker(wxPanel* panel, nlohmann::json j, int y); + nlohmann::json GetConfig() override; + void SetConfig(nlohmann::json config) override; +}; + +class DirPicker : public Component { +public: + wxString GetRawString() override; + DirPicker(wxPanel* panel, nlohmann::json j, int y); + nlohmann::json GetConfig() override; + void SetConfig(nlohmann::json config) override; +}; + +class Choice : public Component { +public: + wxString GetRawString() override; + Choice(wxPanel* panel, nlohmann::json j, int y); + nlohmann::json GetConfig() override; + void SetConfig(nlohmann::json config) override; +}; + +class CheckBox : public Component { +public: + wxString GetRawString() override; + CheckBox(wxPanel* panel, nlohmann::json j, int y); + nlohmann::json GetConfig() override; + void SetConfig(nlohmann::json config) override; +}; + +class CheckBoxes : public Component { +public: + wxString GetRawString() override; + CheckBoxes(wxPanel* panel, nlohmann::json j, int y); + nlohmann::json GetConfig() override; + void SetConfig(nlohmann::json config) override; +}; \ No newline at end of file diff --git a/src/JsonUtils.cpp b/src/JsonUtils.cpp index 0e2da10..821526a 100644 --- a/src/JsonUtils.cpp +++ b/src/JsonUtils.cpp @@ -25,7 +25,7 @@ namespace jsonUtils { } ostream << std::setw(4) << json << std::endl; ostream.close(); - return true + return true; } bool hasKey(nlohmann::json json, std::string key) { diff --git a/src/MainFrame.cpp b/src/MainFrame.cpp index da8376f..537858e 100644 --- a/src/MainFrame.cpp +++ b/src/MainFrame.cpp @@ -85,7 +85,7 @@ MainFrame::MainFrame() //put components mainPanel = new wxPanel(this); - components = std::vector(); + components = std::vector(); int y = UpdatePanel(mainPanel); runButton = new wxButton(mainPanel, wxID_EXECUTE, wxString::FromUTF8(sub_definition["button"]), wxPoint(143, y), wxSize(105, 25)); @@ -153,8 +153,8 @@ void MainFrame::LoadDefinition() { } void MainFrame::UpdateConfig() { - for (Component c: components){ - config[c.GetLabel()] = c.GetConfig(); + for (Component* c: components){ + config[c->GetLabel()] = c->GetConfig(); } } @@ -213,14 +213,14 @@ void MainFrame::RunCommand(wxCommandEvent& event) { std::vector cmd_ary = split(sub_definition["command"], '%'); wxString cmd = ""; int i = 0; - for (Component c : components) { - if (c.HasString()) { + for (Component* c : components) { + if (c->HasString()) { if (cmd_ary.size() <= i) { std::cout << "[RunCommand]: Json format error (Can not make command)" << std::endl; ShowErrorDialog("Json format error (Can not make command)"); return; } - cmd += cmd_ary[i] + c.GetString(); + cmd += cmd_ary[i] + c->GetString(); i += 1; } } @@ -325,7 +325,7 @@ int MainFrame::UpdatePanel(wxPanel* panel) if (jsonUtils::hasKey(config, newComp->GetLabel())) { newComp->SetConfig(config[newComp->GetLabel()]); } - components.push_back(*newComp); + components.push_back(newComp); } } diff --git a/src/MainFrame.h b/src/MainFrame.h index ecff407..4270fd8 100644 --- a/src/MainFrame.h +++ b/src/MainFrame.h @@ -32,7 +32,7 @@ class MainFrame : public wxFrame #ifdef __linux__ LogFrame* logFrame; #endif - std::vector components; + std::vector components; wxPanel* mainPanel; wxButton* runButton; From 6065a4a6af82e322d4a0add974c847c1c76cbc6f Mon Sep 17 00:00:00 2001 From: matyalatte Date: Wed, 11 May 2022 07:18:37 +0900 Subject: [PATCH 3/5] add textbux, change json format, bug fix --- changelog.txt | 7 +++ samples/advanced/gui_definition.json | 11 +++-- src/Component.cpp | 59 ++++++++++++++++++------- src/Component.h | 16 +++++-- src/JsonUtils.cpp | 65 ++++++++++++++++++---------- src/JsonUtils.h | 4 +- src/MainFrame.cpp | 49 ++++++++++----------- 7 files changed, 134 insertions(+), 77 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7a158d6..7571b08 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +ver0.1.1 +- Added textbox to GUI components +- Changed json format +- Fixed an error when reading utf-16 strings from stdout +- Fixed a bug can't read configs for checkboxes + + ver0.1.0 - Added support for mac and linux (ubuntu) - Added console window for linux diff --git a/samples/advanced/gui_definition.json b/samples/advanced/gui_definition.json index d3ba375..fe918e1 100644 --- a/samples/advanced/gui_definition.json +++ b/samples/advanced/gui_definition.json @@ -8,7 +8,7 @@ "button": "Echo!", "components": [ { - "type": "text", + "type": "static_text", "label": "This is a sample GUI. Edit 'gui_definition.json' for your scripts." }, { @@ -37,12 +37,12 @@ { "label": "Sample GUI2", "window_name": "Simple Command Runner", - "command": "echo \"num: %hoo%\" & echo \"file: %bar%\" & echo \"Sample message!\"", + "command": "echo \"num: %hoo%\" & echo \"text: %bar%\" & echo \"Sample message!\"", "button": "Echo!", "show_last_line": true, "components": [ { - "type": "text", + "type": "static_text", "label": "This is a sample GUI. Edit 'gui_definition.json' for your scripts." }, { @@ -53,9 +53,8 @@ "default": 1 }, { - "type": "file", - "label": "Some file path", - "extension": "any files | *" + "type": "text", + "label": "Some text" } ] } diff --git a/src/Component.cpp b/src/Component.cpp index 55c7e9f..f912d9f 100644 --- a/src/Component.cpp +++ b/src/Component.cpp @@ -88,9 +88,10 @@ bool Component::HasString() { } Component* Component::PutComponent(wxPanel* panel, nlohmann::json j, int y) { + Component* comp=nullptr; - if (j["type"] == "text") {//text - comp = new Text(panel, j, y); + if (j["type"] == "static_text") {//statc text + comp = new StaticText(panel, j, y); } else if (j["type"] == "file") {//file picker comp = new FilePicker(panel, j, y); @@ -104,11 +105,14 @@ Component* Component::PutComponent(wxPanel* panel, nlohmann::json j, int y) { else if (j["type"] == "check") {//checkbox comp = new CheckBox(panel, j, y); } - else if (j["type"] == "checks") {//checkboxes - comp = new CheckBoxes(panel, j, y); + else if (j["type"] == "check_array") {//checkArray + comp = new CheckArray(panel, j, y); + } + else if (j["type"] == "text") {//text box + comp = new TextBox(panel, j, y); } else { - std::cout << "[UpdatePanel] unknown component type detected. (" << j["type"] << ")" << std::endl; + std::cout << "[UpdatePanel] Unknown component type detected. (" << j["type"] << ")" << std::endl; } return comp; } @@ -116,12 +120,12 @@ Component* Component::PutComponent(wxPanel* panel, nlohmann::json j, int y) { const bool HAS_STRING = true; const bool NOT_STRING = false; -Text::Text(wxPanel* panel, nlohmann::json j, int y): Component(j, 25, NOT_STRING) { +StaticText::StaticText(wxPanel* panel, nlohmann::json j, int y): Component(j, 25, NOT_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); } //File Picker -FilePicker::FilePicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 50, HAS_STRING) { +FilePicker::FilePicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 53, HAS_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); wxString ext; if (jsonUtils::hasKey(j, "extension")) { @@ -130,7 +134,7 @@ FilePicker::FilePicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 5 else { ext = "any files | *"; } - wxFilePickerCtrl* picker = new wxFilePickerCtrl(panel, wxID_ANY, "", "", ext, wxPoint(20, y + 15), wxSize(350, 25), wxFLP_DEFAULT_STYLE | wxFLP_USE_TEXTCTRL); + wxFilePickerCtrl* picker = new wxFilePickerCtrl(panel, wxID_ANY, "", "", ext, wxPoint(20, y + 18), wxSize(350, 25), wxFLP_DEFAULT_STYLE | wxFLP_USE_TEXTCTRL); picker->GetTextCtrl()->SetDropTarget(new DropFilePath(picker)); picker->DragAcceptFiles(true); widget = picker; @@ -159,9 +163,9 @@ nlohmann::json FilePicker::GetConfig() { } //Dir Picker -DirPicker::DirPicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 50, HAS_STRING) { +DirPicker::DirPicker(wxPanel* panel, nlohmann::json j, int y) : Component(j, 53, HAS_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); - wxDirPickerCtrl* picker = new wxDirPickerCtrl(panel, wxID_ANY, "", "", wxPoint(20, y + 15), wxSize(350, 25), wxDIRP_DEFAULT_STYLE | wxDIRP_USE_TEXTCTRL); + wxDirPickerCtrl* picker = new wxDirPickerCtrl(panel, wxID_ANY, "", "", wxPoint(20, y + 18), wxSize(350, 25), wxDIRP_DEFAULT_STYLE | wxDIRP_USE_TEXTCTRL); picker->GetTextCtrl()->SetDropTarget(new DropFilePath(picker)); picker->DragAcceptFiles(true); widget = picker; @@ -265,8 +269,8 @@ nlohmann::json CheckBox::GetConfig() { return config; } -//CheckBoxes -CheckBoxes::CheckBoxes(wxPanel* panel, nlohmann::json j, int y) : Component(j, 20 + j["items"].size() * 20 + 10, HAS_STRING) { +//CheckArray +CheckArray::CheckArray(wxPanel* panel, nlohmann::json j, int y) : Component(j, 20 + j["items"].size() * 20 + 10, HAS_STRING) { wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); std::vector* checks = new std::vector(); wxCheckBox* check; @@ -283,7 +287,7 @@ CheckBoxes::CheckBoxes(wxPanel* panel, nlohmann::json j, int y) : Component(j, 2 widget = checks; } -wxString CheckBoxes::GetRawString() { +wxString CheckArray::GetRawString() { wxString str = ""; std::vector checks; checks = *(std::vector*)widget; @@ -295,9 +299,9 @@ wxString CheckBoxes::GetRawString() { return str; } -void CheckBoxes::SetConfig(nlohmann::json config) { +void CheckArray::SetConfig(nlohmann::json config) { std::vector checks; - if (jsonUtils::hasKey(config, "ints") && config["int"].is_array()) { + if (jsonUtils::hasKey(config, "ints") && config["ints"].is_array()) { checks = *(std::vector*)widget; for (int i = 0; i < config["ints"].size() && i < checks.size(); i++) { checks[i]->SetValue(config["ints"][i] != 0); @@ -305,7 +309,7 @@ void CheckBoxes::SetConfig(nlohmann::json config) { } } -nlohmann::json CheckBoxes::GetConfig() { +nlohmann::json CheckArray::GetConfig() { nlohmann::json config = {}; std::vector ints; for (wxCheckBox* check : *(std::vector*)widget) { @@ -313,4 +317,27 @@ nlohmann::json CheckBoxes::GetConfig() { } config["ints"] = ints; return config; +} + +//TextBox +TextBox::TextBox(wxPanel* panel, nlohmann::json j, int y) : Component(j, 53, HAS_STRING) { + wxStaticText* text = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(j["label"]), wxPoint(20, y)); + wxTextCtrl* textbox = new wxTextCtrl(panel, wxID_ANY, "", wxPoint(20, y + 20), wxSize(350, 23)); + widget = textbox; +} + +wxString TextBox::GetRawString() { + return ((wxTextCtrl*)widget)->GetValue(); +} + +void TextBox::SetConfig(nlohmann::json config) { + if (jsonUtils::hasKey(config, "str") && config["str"].is_string()) { + ((wxTextCtrl*)widget)->SetValue(config["str"]); + } +} + +nlohmann::json TextBox::GetConfig() { + nlohmann::json config = {}; + config["str"] = ((wxTextCtrl*)widget)->GetValue(); + return config; } \ No newline at end of file diff --git a/src/Component.h b/src/Component.h index c31b25b..2ea0ea7 100644 --- a/src/Component.h +++ b/src/Component.h @@ -60,9 +60,9 @@ std::string wstring_to_utf8(const std::wstring& str); std::wstring utf8_to_wstring(const std::string& str); #endif -class Text : public Component { +class StaticText : public Component { public: - Text(wxPanel* panel, nlohmann::json j, int y); + StaticText(wxPanel* panel, nlohmann::json j, int y); }; class FilePicker : public Component { @@ -97,10 +97,18 @@ class CheckBox : public Component { void SetConfig(nlohmann::json config) override; }; -class CheckBoxes : public Component { +class CheckArray : public Component { public: wxString GetRawString() override; - CheckBoxes(wxPanel* panel, nlohmann::json j, int y); + CheckArray(wxPanel* panel, nlohmann::json j, int y); + nlohmann::json GetConfig() override; + void SetConfig(nlohmann::json config) override; +}; + +class TextBox : public Component { +public: + wxString GetRawString() override; + TextBox(wxPanel* panel, nlohmann::json j, int y); nlohmann::json GetConfig() override; void SetConfig(nlohmann::json config) override; }; \ No newline at end of file diff --git a/src/JsonUtils.cpp b/src/JsonUtils.cpp index 821526a..c1f0fd7 100644 --- a/src/JsonUtils.cpp +++ b/src/JsonUtils.cpp @@ -50,7 +50,34 @@ namespace jsonUtils { return def; } - std::string checkSubDefinition(nlohmann::json sub_definition) { + std::string checkItemsValues(nlohmann::json& c) { + std::string label = c["label"]; + if (!hasKey(c, "items")) { + if (hasKey(c, "item")) { + c["items"] = c["item"]; + } + else { + return label + "['items'] not found."; + } + } + if (!c["items"].is_array()) { + return label + "['items'] should be an array."; + } + if (!hasKey(c, "values") && hasKey(c, "value")) { + c["values"] = c["value"]; + } + if (hasKey(c, "values")) { + if (!c["values"].is_array()) { + return label + "['values'] should be an array."; + } + if (c["values"].size() != c["items"].size()) { + return label + "['values'] and " + label + "['items'] should have the same size."; + } + } + return "__null__"; + } + + std::string checkSubDefinition(nlohmann::json& sub_definition) { //check if keys exist std::vector keys = { "label", "button", "command", "components" }; for (std::string key : keys) { @@ -87,7 +114,8 @@ namespace jsonUtils { keys = { "type", "label" }; std::vector subkeys = {}; std::string label; - for (nlohmann::json c : sub_definition["components"]) { + std::string msg; + for (nlohmann::json& c : sub_definition["components"]) { //check if type and label exist for (std::string key : keys) { if (!hasKey(c, key)) { @@ -104,11 +132,10 @@ namespace jsonUtils { } } else if (c["type"] == "choice") { - subkeys = { "items", "values" }; - for (std::string key : subkeys) { - if (hasKey(c, key) && !c[key].is_array()) { - return label + "['" + key + "'] should be an array."; - } + + msg = checkItemsValues(c); + if (msg != "__null__") { + return msg; } subkeys = { "width", "default" }; for (std::string key : subkeys) { @@ -122,22 +149,16 @@ namespace jsonUtils { return label + "['value'] should be a string."; } } - else if (c["type"] == "checks") { - if (!hasKey(c, "items")) { - return label + "['items'] not found."; - } - if (!c["items"].is_array()) { - return label + "['items'] should be an array."; - } - if (hasKey(c, "values")) { - if (!c["values"].is_array()) { - return label + "['values'] should be an array."; - } - if (c["values"].size() != c["items"].size()) { - return label + "['values'] and " + label + "['items'] should have the same size."; - } + else if (c["type"] == "checks" || c["type"] == "check_array") { + c["type"] = "check_array"; + msg = checkItemsValues(c); + if (msg != "__null__") { + return msg; } } + else if (c["type"] == "text_box") { + c["type"] = "text"; + } if (hasKey(c, "add_quotes") && !c["add_quotes"].is_boolean()) { return label + "['add_quotes'] should be a boolean."; } @@ -145,7 +166,7 @@ namespace jsonUtils { return "__null__"; } - std::string checkHelpURLs(nlohmann::json definition) { + std::string checkHelpURLs(nlohmann::json& definition) { if (!definition["help"].is_array()) { return "'help' should be an array."; } diff --git a/src/JsonUtils.h b/src/JsonUtils.h index e41b068..2a25a5b 100644 --- a/src/JsonUtils.h +++ b/src/JsonUtils.h @@ -10,6 +10,6 @@ namespace jsonUtils { bool hasKey(nlohmann::json json, std::string key); nlohmann::json default_definition(); - std::string checkSubDefinition(nlohmann::json sub_definition); - std::string checkHelpURLs(nlohmann::json definition); + std::string checkSubDefinition(nlohmann::json& sub_definition); + std::string checkHelpURLs(nlohmann::json& definition); } \ No newline at end of file diff --git a/src/MainFrame.cpp b/src/MainFrame.cpp index 537858e..71d059c 100644 --- a/src/MainFrame.cpp +++ b/src/MainFrame.cpp @@ -1,6 +1,6 @@ #include "MainFrame.h" -const char* VERSION = "0.1.0"; +const char* VERSION = "0.1.1"; //Console window for unix #ifdef __linux__ @@ -115,19 +115,6 @@ void MainFrame::LoadDefinition() { return; } - //check format - if (jsonUtils::hasKey(definition, "gui") && definition["gui"].is_array()) { - sub_definition = definition["gui"][0]; - } - else { - msg = "Fialed to load gui_definition.json ('gui' array not found.)"; - std::cout << "[LoadDefinition] " << msg << std::endl; - ShowErrorDialog(msg); - sub_definition = jsonUtils::default_definition(); - definition = { { "gui", {sub_definition}} }; - return; - } - //check help urls if (jsonUtils::hasKey(definition, "help")) { msg = jsonUtils::checkHelpURLs(definition); @@ -140,15 +127,30 @@ void MainFrame::LoadDefinition() { } } - //check panel definitions - msg = jsonUtils::checkSubDefinition(sub_definition); - if (msg!="__null__") { - msg = "Fialed to load gui_definition.json ("+ msg +")"; + //check format + if (!jsonUtils::hasKey(definition, "gui") || !definition["gui"].is_array()) { + msg = "Fialed to load gui_definition.json ('gui' array not found.)"; std::cout << "[LoadDefinition] " << msg << std::endl; ShowErrorDialog(msg); sub_definition = jsonUtils::default_definition(); + definition["gui"] = {sub_definition}; return; } + + //check panel definitions + for (nlohmann::json& sub_d : definition["gui"]) { + msg = jsonUtils::checkSubDefinition(sub_d); + if (msg != "__null__") { + msg = "Fialed to load gui_definition.json (" + msg + ")"; + std::cout << "[LoadDefinition] " << msg << std::endl; + ShowErrorDialog(msg); + sub_definition = jsonUtils::default_definition(); + definition["gui"] = {sub_definition}; + return; + } + } + sub_definition = definition["gui"][0]; + std::cout << "[LoadDefinition] Loaded gui_definition.json" << std::endl; } @@ -257,7 +259,8 @@ void MainFrame::RunCommand(wxCommandEvent& event) { } } -MainFrame::~MainFrame(){} +MainFrame::~MainFrame(){ +} void MainFrame::OpenURL(wxCommandEvent& event) { wxString url = wxString::FromUTF8(definition["help"][event.GetId() - 1 - wxID_HIGHEST - definition["gui"].size()]["url"]); @@ -268,14 +271,6 @@ void MainFrame::OpenURL(wxCommandEvent& event) { void MainFrame::UpdateFrame(wxCommandEvent& event) { sub_definition = definition["gui"][event.GetId() - 1 - wxID_HIGHEST]; - std::string msg = jsonUtils::checkSubDefinition(sub_definition); - if (msg != "__null__") { - msg = "Json format error(" + msg + ")"; - std::cout << "[UpdateFrame] " << msg << std::endl; - ShowErrorDialog(msg); - sub_definition = jsonUtils::default_definition(); - return; - } UpdateConfig(); From 2d35496885d1550a001d6ee3d9f30f8355c7ce08 Mon Sep 17 00:00:00 2001 From: matyalatte Date: Wed, 11 May 2022 20:26:56 +0900 Subject: [PATCH 4/5] change command format --- build.bat | 1 + changelog.txt | 1 - src/JsonUtils.cpp | 32 +++++++++++++++++++++++++++++--- src/MainFrame.cpp | 23 +---------------------- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/build.bat b/build.bat index e107562..1845ce6 100644 --- a/build.bat +++ b/build.bat @@ -15,6 +15,7 @@ cmake -G "%VS_VERSION%"^ ../ REM build with VS + "%MSBUILD%" SimpleCommandRunner.vcxproj /t:build /p:configuration=Release /p:platform=x64 -maxcpucount pause diff --git a/changelog.txt b/changelog.txt index 7571b08..e721177 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,6 @@ ver0.1.1 - Fixed an error when reading utf-16 strings from stdout - Fixed a bug can't read configs for checkboxes - ver0.1.0 - Added support for mac and linux (ubuntu) - Added console window for linux diff --git a/src/JsonUtils.cpp b/src/JsonUtils.cpp index c1f0fd7..b69874c 100644 --- a/src/JsonUtils.cpp +++ b/src/JsonUtils.cpp @@ -39,10 +39,10 @@ namespace jsonUtils { { {"label", "Default GUI"}, #ifdef _WIN32 - {"command", "dir" }, + {"command", {"dir"} }, {"button", "run 'dir'"}, #else - {"command", "ls" }, + {"command", {"ls"} }, {"button", "run 'ls'"}, #endif {"components",{}} @@ -76,6 +76,25 @@ namespace jsonUtils { } return "__null__"; } + + std::vector split(const std::string& s, const char delimiter) + { + std::vector tokens; + std::string token; + std::istringstream tokenStream(s); + bool store = true; + while (std::getline(tokenStream, token, delimiter)) + { + if (store) { + tokens.push_back(token); + store = false; + } + else { + store = true; + } + } + return tokens; + } std::string checkSubDefinition(nlohmann::json& sub_definition) { //check if keys exist @@ -87,7 +106,7 @@ namespace jsonUtils { } //check is_string - keys = { "label", "button", "command" }; + keys = { "label", "button"}; if (hasKey(sub_definition, "window_name")) { keys.push_back("window_name"); } @@ -97,6 +116,13 @@ namespace jsonUtils { } } + if (sub_definition["command"].is_string()) { + sub_definition["command"] = split(sub_definition["command"], '%'); + } + if (!sub_definition["command"].is_array()) { + return "'command' should be a string or an string array."; + } + //check is_boolean if (hasKey(sub_definition, "show_last_line") && !sub_definition["show_last_line"].is_boolean()) { return "'show_last_line' should be a boolean."; diff --git a/src/MainFrame.cpp b/src/MainFrame.cpp index 71d059c..d27dc8d 100644 --- a/src/MainFrame.cpp +++ b/src/MainFrame.cpp @@ -184,27 +184,6 @@ void MainFrame::ShowSuccessDialog(wxString msg) { dialog->Destroy(); } - - -std::vector split(const std::string& s, const char delimiter) -{ - std::vector tokens; - std::string token; - std::istringstream tokenStream(s); - bool store = true; - while (std::getline(tokenStream, token, delimiter)) - { - if (store) { - tokens.push_back(token); - store = false; - } - else { - store = true; - } - } - return tokens; -} - //run command void MainFrame::RunCommand(wxCommandEvent& event) { //save config @@ -212,7 +191,7 @@ void MainFrame::RunCommand(wxCommandEvent& event) { SaveConfig(); //make command string - std::vector cmd_ary = split(sub_definition["command"], '%'); + std::vector cmd_ary = sub_definition["command"]; wxString cmd = ""; int i = 0; for (Component* c : components) { From fe33a2b95377736e48feeb9ca42cfc4699b0b0d0 Mon Sep 17 00:00:00 2001 From: matyalatte Date: Wed, 11 May 2022 20:31:50 +0900 Subject: [PATCH 5/5] update documents --- README.md | 2 +- samples/advanced/gui_definition.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 21f869f..46b9e63 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![build](https://github.com/matyalatte/Simple-Command-Runner/actions/workflows/build_windows.yml/badge.svg) ![build](https://github.com/matyalatte/Simple-Command-Runner/actions/workflows/build_ubuntu.yml/badge.svg) ![build](https://github.com/matyalatte/Simple-Command-Runner/actions/workflows/build_mac.yml/badge.svg) -# Simple-Command-Runner ver 0.1.0 +# Simple-Command-Runner ver 0.1.1 Simple GUI builder to execute commands.
## About diff --git a/samples/advanced/gui_definition.json b/samples/advanced/gui_definition.json index fe918e1..68d8185 100644 --- a/samples/advanced/gui_definition.json +++ b/samples/advanced/gui_definition.json @@ -53,7 +53,7 @@ "default": 1 }, { - "type": "text", + "type": "text_box", "label": "Some text" } ]