@@ -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); | ||||