| @@ -26,7 +26,7 @@ plugin::Model* createModel(const std::string& slug) { | |||||
| return m; | return m; | ||||
| } | } | ||||
| app::ModuleWidget* createModuleWidget(engine::Module* m) override { | app::ModuleWidget* createModuleWidget(engine::Module* m) override { | ||||
| TModule *tm = NULL; | |||||
| TModule* tm = NULL; | |||||
| if (m) { | if (m) { | ||||
| assert(m->model == this); | assert(m->model == this); | ||||
| tm = dynamic_cast<TModule*>(m); | tm = dynamic_cast<TModule*>(m); | ||||
| @@ -611,8 +611,6 @@ PortWidget* ModuleWidget::getOutput(int portId) { | |||||
| json_t* ModuleWidget::toJson() { | json_t* ModuleWidget::toJson() { | ||||
| json_t* moduleJ = APP->engine->moduleToJson(module); | json_t* moduleJ = APP->engine->moduleToJson(module); | ||||
| // When serializing ModuleWidget, don't include the ID. This ID is only meaningful when serializing the entire rack. | |||||
| json_object_del(moduleJ, "id"); | |||||
| return moduleJ; | return moduleJ; | ||||
| } | } | ||||
| @@ -622,13 +620,9 @@ void ModuleWidget::fromJson(json_t* rootJ) { | |||||
| void ModuleWidget::copyClipboard() { | void ModuleWidget::copyClipboard() { | ||||
| json_t* moduleJ = toJson(); | json_t* moduleJ = toJson(); | ||||
| DEFER({ | |||||
| json_decref(moduleJ); | |||||
| }); | |||||
| DEFER({json_decref(moduleJ);}); | |||||
| char* moduleJson = json_dumps(moduleJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | char* moduleJson = json_dumps(moduleJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | ||||
| DEFER({ | |||||
| free(moduleJson); | |||||
| }); | |||||
| DEFER({std::free(moduleJson);}); | |||||
| glfwSetClipboardString(APP->window->win, moduleJson); | glfwSetClipboardString(APP->window->win, moduleJson); | ||||
| } | } | ||||
| @@ -645,9 +639,12 @@ void ModuleWidget::pasteClipboardAction() { | |||||
| WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | ||||
| return; | return; | ||||
| } | } | ||||
| DEFER({ | |||||
| json_decref(moduleJ); | |||||
| }); | |||||
| DEFER({json_decref(moduleJ);}); | |||||
| // Don't use IDs from JSON | |||||
| json_object_del(moduleJ, "id"); | |||||
| json_object_del(moduleJ, "leftModuleId"); | |||||
| json_object_del(moduleJ, "rightModuleId"); | |||||
| // history::ModuleChange | // history::ModuleChange | ||||
| history::ModuleChange* h = new history::ModuleChange; | history::ModuleChange* h = new history::ModuleChange; | ||||
| @@ -665,9 +662,7 @@ void ModuleWidget::load(std::string filename) { | |||||
| FILE* file = std::fopen(filename.c_str(), "r"); | FILE* file = std::fopen(filename.c_str(), "r"); | ||||
| if (!file) | if (!file) | ||||
| throw Exception(string::f("Could not load patch file %s", filename.c_str())); | throw Exception(string::f("Could not load patch file %s", filename.c_str())); | ||||
| DEFER({ | |||||
| std::fclose(file); | |||||
| }); | |||||
| DEFER({std::fclose(file);}); | |||||
| INFO("Loading preset %s", filename.c_str()); | INFO("Loading preset %s", filename.c_str()); | ||||
| @@ -675,9 +670,12 @@ void ModuleWidget::load(std::string filename) { | |||||
| json_t* moduleJ = json_loadf(file, 0, &error); | json_t* moduleJ = json_loadf(file, 0, &error); | ||||
| if (!moduleJ) | if (!moduleJ) | ||||
| throw Exception(string::f("File is not a valid patch file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text)); | throw Exception(string::f("File is not a valid patch file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text)); | ||||
| DEFER({ | |||||
| json_decref(moduleJ); | |||||
| }); | |||||
| DEFER({json_decref(moduleJ);}); | |||||
| // Don't use IDs from JSON | |||||
| json_object_del(moduleJ, "id"); | |||||
| json_object_del(moduleJ, "leftModuleId"); | |||||
| json_object_del(moduleJ, "rightModuleId"); | |||||
| fromJson(moduleJ); | fromJson(moduleJ); | ||||
| } | } | ||||
| @@ -729,7 +727,7 @@ void ModuleWidget::loadDialog() { | |||||
| // No path selected | // No path selected | ||||
| return; | return; | ||||
| } | } | ||||
| DEFER({free(pathC);}); | |||||
| DEFER({std::free(pathC);}); | |||||
| try { | try { | ||||
| loadAction(pathC); | loadAction(pathC); | ||||
| @@ -744,17 +742,13 @@ void ModuleWidget::save(std::string filename) { | |||||
| json_t* moduleJ = toJson(); | json_t* moduleJ = toJson(); | ||||
| assert(moduleJ); | assert(moduleJ); | ||||
| DEFER({ | |||||
| json_decref(moduleJ); | |||||
| }); | |||||
| DEFER({json_decref(moduleJ);}); | |||||
| FILE* file = fopen(filename.c_str(), "w"); | |||||
| FILE* file = std::fopen(filename.c_str(), "w"); | |||||
| if (!file) { | if (!file) { | ||||
| WARN("Could not write to patch file %s", filename.c_str()); | WARN("Could not write to patch file %s", filename.c_str()); | ||||
| } | } | ||||
| DEFER({ | |||||
| fclose(file); | |||||
| }); | |||||
| DEFER({std::fclose(file);}); | |||||
| json_dumpf(moduleJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | json_dumpf(moduleJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | ||||
| } | } | ||||
| @@ -786,7 +780,7 @@ void ModuleWidget::saveDialog() { | |||||
| // No path selected | // No path selected | ||||
| return; | return; | ||||
| } | } | ||||
| DEFER({free(pathC);}); | |||||
| DEFER({std::free(pathC);}); | |||||
| std::string path = pathC; | std::string path = pathC; | ||||
| if (system::getExtension(path) == "") | if (system::getExtension(path) == "") | ||||
| @@ -872,15 +866,18 @@ void ModuleWidget::cloneAction() { | |||||
| // history::ComplexAction | // history::ComplexAction | ||||
| history::ComplexAction* h = new history::ComplexAction; | history::ComplexAction* h = new history::ComplexAction; | ||||
| // Clone Module | |||||
| engine::Module* clonedModule = model->createModule(); | |||||
| // JSON serialization is the obvious way to do this | // JSON serialization is the obvious way to do this | ||||
| json_t* moduleJ = toJson(); | json_t* moduleJ = toJson(); | ||||
| // Don't use IDs from JSON | |||||
| json_object_del(moduleJ, "id"); | |||||
| json_object_del(moduleJ, "leftModuleId"); | |||||
| json_object_del(moduleJ, "rightModuleId"); | |||||
| // Clone Module | |||||
| engine::Module* clonedModule = model->createModule(); | |||||
| // This doesn't need a lock (via Engine::moduleFromJson()) because the Module is not added to the Engine yet. | // This doesn't need a lock (via Engine::moduleFromJson()) because the Module is not added to the Engine yet. | ||||
| clonedModule->fromJson(moduleJ); | clonedModule->fromJson(moduleJ); | ||||
| json_decref(moduleJ); | json_decref(moduleJ); | ||||
| // Reset ID so the Engine automatically assigns a new one | |||||
| clonedModule->id = -1; | |||||
| APP->engine->addModule(clonedModule); | APP->engine->addModule(clonedModule); | ||||
| // Clone ModuleWidget | // Clone ModuleWidget | ||||
| @@ -22,8 +22,9 @@ namespace app { | |||||
| /** Creates a new Module and ModuleWidget */ | /** Creates a new Module and ModuleWidget */ | ||||
| ModuleWidget* moduleWidgetFromJson(json_t* moduleJ) { | |||||
| static ModuleWidget* moduleWidgetFromJson(json_t* moduleJ) { | |||||
| plugin::Model* model = plugin::modelFromJson(moduleJ); | plugin::Model* model = plugin::modelFromJson(moduleJ); | ||||
| assert(model); | |||||
| engine::Module* module = model->createModule(); | engine::Module* module = model->createModule(); | ||||
| assert(module); | assert(module); | ||||
| module->fromJson(moduleJ); | module->fromJson(moduleJ); | ||||
| @@ -287,10 +288,12 @@ void RackWidget::fromJson(json_t* rootJ) { | |||||
| } | } | ||||
| CableWidget* cw = new CableWidget; | CableWidget* cw = new CableWidget; | ||||
| // Legacy: Before v1, cable colors were not serialized. So we need to initialize the color here. | |||||
| cw->setNextCableColor(); | |||||
| cw->setCable(cable); | cw->setCable(cable); | ||||
| cw->fromJson(cableJ); | cw->fromJson(cableJ); | ||||
| // In <=v1, cable colors were not serialized, so choose one from the available colors. | |||||
| if (cw->color.a == 0.f) { | |||||
| cw->setNextCableColor(); | |||||
| } | |||||
| addCable(cw); | addCable(cw); | ||||
| } | } | ||||
| } | } | ||||
| @@ -308,20 +311,19 @@ void RackWidget::pastePresetClipboardAction() { | |||||
| WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | ||||
| return; | return; | ||||
| } | } | ||||
| DEFER({ | |||||
| json_decref(moduleJ); | |||||
| }); | |||||
| DEFER({json_decref(moduleJ);}); | |||||
| // Because we are creating a new module, we don't want to use the IDs from the JSON. | |||||
| json_object_del(moduleJ, "id"); | |||||
| json_object_del(moduleJ, "leftModuleId"); | |||||
| json_object_del(moduleJ, "rightModuleId"); | |||||
| try { | try { | ||||
| plugin::Model* model = plugin::modelFromJson(moduleJ); | |||||
| engine::Module* module = model->createModule(); | |||||
| assert(module); | |||||
| module->fromJson(moduleJ); | |||||
| // Reset ID so the Engine automatically assigns a new one | |||||
| module->id = -1; | |||||
| APP->engine->addModule(module); | |||||
| ModuleWidget* mw = module->model->createModuleWidget(module); | |||||
| ModuleWidget* mw = moduleWidgetFromJson(moduleJ); | |||||
| assert(mw); | |||||
| assert(mw->module); | |||||
| APP->engine->addModule(mw->module); | |||||
| addModuleAtMouse(mw); | addModuleAtMouse(mw); | ||||
| // history::ModuleAdd | // history::ModuleAdd | ||||
| @@ -152,13 +152,10 @@ void Module::fromJson(json_t* rootJ) { | |||||
| } | } | ||||
| } | } | ||||
| // Only set ID if unset | |||||
| if (id < 0) { | |||||
| // id | |||||
| json_t* idJ = json_object_get(rootJ, "id"); | |||||
| if (idJ) | |||||
| id = json_integer_value(idJ); | |||||
| } | |||||
| // id | |||||
| json_t* idJ = json_object_get(rootJ, "id"); | |||||
| if (idJ) | |||||
| id = json_integer_value(idJ); | |||||
| // params | // params | ||||
| json_t* paramsJ = json_object_get(rootJ, "params"); | json_t* paramsJ = json_object_get(rootJ, "params"); | ||||
| @@ -176,16 +173,15 @@ void Module::fromJson(json_t* rootJ) { | |||||
| if (bypassedJ) | if (bypassedJ) | ||||
| internal->bypassed = json_boolean_value(bypassedJ); | internal->bypassed = json_boolean_value(bypassedJ); | ||||
| // These do not need to be deserialized, since the module positions will set them correctly when added to the rack. | |||||
| // // leftModuleId | |||||
| // json_t *leftModuleIdJ = json_object_get(rootJ, "leftModuleId"); | |||||
| // if (leftModuleIdJ) | |||||
| // leftExpander.moduleId = json_integer_value(leftModuleIdJ); | |||||
| // leftModuleId | |||||
| json_t *leftModuleIdJ = json_object_get(rootJ, "leftModuleId"); | |||||
| if (leftModuleIdJ) | |||||
| leftExpander.moduleId = json_integer_value(leftModuleIdJ); | |||||
| // // rightModuleId | |||||
| // json_t *rightModuleIdJ = json_object_get(rootJ, "rightModuleId"); | |||||
| // if (rightModuleIdJ) | |||||
| // rightExpander.moduleId = json_integer_value(rightModuleIdJ); | |||||
| // rightModuleId | |||||
| json_t *rightModuleIdJ = json_object_get(rootJ, "rightModuleId"); | |||||
| if (rightModuleIdJ) | |||||
| rightExpander.moduleId = json_integer_value(rightModuleIdJ); | |||||
| // data | // data | ||||
| json_t* dataJ = json_object_get(rootJ, "data"); | json_t* dataJ = json_object_get(rootJ, "data"); | ||||
| @@ -101,9 +101,7 @@ bool isTruncated() { | |||||
| FILE* file = std::fopen(asset::logPath.c_str(), "r"); | FILE* file = std::fopen(asset::logPath.c_str(), "r"); | ||||
| if (!file) | if (!file) | ||||
| return false; | return false; | ||||
| DEFER({ | |||||
| std::fclose(file); | |||||
| }); | |||||
| DEFER({std::fclose(file);}); | |||||
| if (fileEndsWith(file, "END")) | if (fileEndsWith(file, "END")) | ||||
| return false; | return false; | ||||
| @@ -4,6 +4,7 @@ | |||||
| #include <curl/curl.h> | #include <curl/curl.h> | ||||
| #include <network.hpp> | #include <network.hpp> | ||||
| #include <system.hpp> | |||||
| #include <asset.hpp> | #include <asset.hpp> | ||||
| @@ -160,7 +161,7 @@ static int xferInfoCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, | |||||
| bool requestDownload(const std::string& url, const std::string& filename, float* progress, const CookieMap& cookies) { | bool requestDownload(const std::string& url, const std::string& filename, float* progress, const CookieMap& cookies) { | ||||
| CURL* curl = createCurl(); | CURL* curl = createCurl(); | ||||
| FILE* file = fopen(filename.c_str(), "wb"); | |||||
| FILE* file = std::fopen(filename.c_str(), "wb"); | |||||
| if (!file) | if (!file) | ||||
| return false; | return false; | ||||
| @@ -182,10 +183,10 @@ bool requestDownload(const std::string& url, const std::string& filename, float* | |||||
| CURLcode res = curl_easy_perform(curl); | CURLcode res = curl_easy_perform(curl); | ||||
| curl_easy_cleanup(curl); | curl_easy_cleanup(curl); | ||||
| fclose(file); | |||||
| std::fclose(file); | |||||
| if (res != CURLE_OK) | if (res != CURLE_OK) | ||||
| remove(filename.c_str()); | |||||
| system::remove(filename); | |||||
| return res == CURLE_OK; | return res == CURLE_OK; | ||||
| } | } | ||||
| @@ -273,9 +273,7 @@ void PatchManager::loadAutosave() { | |||||
| // TODO Load template without causing infinite recursion | // TODO Load template without causing infinite recursion | ||||
| return; | return; | ||||
| } | } | ||||
| DEFER({ | |||||
| std::fclose(file); | |||||
| }); | |||||
| DEFER({std::fclose(file);}); | |||||
| json_error_t error; | json_error_t error; | ||||
| json_t* rootJ = json_loadf(file, 0, &error); | json_t* rootJ = json_loadf(file, 0, &error); | ||||
| @@ -260,9 +260,7 @@ void save(const std::string& path) { | |||||
| FILE* file = std::fopen(path.c_str(), "w"); | FILE* file = std::fopen(path.c_str(), "w"); | ||||
| if (!file) | if (!file) | ||||
| return; | return; | ||||
| DEFER({ | |||||
| std::fclose(file); | |||||
| }); | |||||
| DEFER({std::fclose(file);}); | |||||
| json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | ||||
| json_decref(rootJ); | json_decref(rootJ); | ||||
| @@ -273,9 +271,7 @@ void load(const std::string& path) { | |||||
| FILE* file = std::fopen(path.c_str(), "r"); | FILE* file = std::fopen(path.c_str(), "r"); | ||||
| if (!file) | if (!file) | ||||
| return; | return; | ||||
| DEFER({ | |||||
| std::fclose(file); | |||||
| }); | |||||
| DEFER({std::fclose(file);}); | |||||
| json_error_t error; | json_error_t error; | ||||
| json_t* rootJ = json_loadf(file, 0, &error); | json_t* rootJ = json_loadf(file, 0, &error); | ||||