Browse Source

Remove "patchPath" from settings. Store path and unsaved status in patch itself. Fix bug where crash leaves old patch path in settings while new patch is loaded in autosave. Add more dialog messages to PatchManager.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
f44ee3a15a
5 changed files with 90 additions and 67 deletions
  1. +3
    -3
      include/patch.hpp
  2. +0
    -1
      include/settings.hpp
  3. +85
    -47
      src/patch.cpp
  4. +0
    -7
      src/settings.cpp
  5. +2
    -9
      standalone/main.cpp

+ 3
- 3
include/patch.hpp View File

@@ -11,13 +11,12 @@ struct PatchManager {
/** The currently loaded patch file path */
std::string path;
/** Enables certain compatibility behavior based on the value */
int legacy;
int legacy = 0;
std::string warningLog;

PatchManager();
~PatchManager();
/** Resets the history and scroll position to prepare for a new patch. */
void reset();
void launch(std::string pathArg);
/** Clears the patch. */
void clear();
/** Saves the patch and nothing else. */
@@ -34,6 +33,7 @@ struct PatchManager {
/** Loads the template patch. */
void loadTemplate();
void loadTemplateDialog();
bool hasAutosave();
void loadAutosave();
/** Loads a patch, sets the current path, and updates the recent patches. */
void loadAction(std::string path);


+ 0
- 1
include/settings.hpp View File

@@ -58,7 +58,6 @@ extern bool lockModules;
extern int frameSwapInterval;
extern float autosaveInterval;
extern bool skipLoadOnLaunch;
extern std::string patchPath;
extern std::list<std::string> recentPatchPaths;
extern std::vector<NVGcolor> cableColors;
extern bool autoCheckUpdates;


+ 85
- 47
src/patch.cpp View File

@@ -31,22 +31,40 @@ PatchManager::~PatchManager() {
}


void PatchManager::reset() {
if (APP->history) {
APP->history->clear();
void PatchManager::launch(std::string pathArg) {
// Load the argument if exists
if (pathArg != "") {
loadAction(pathArg);
return;
}
if (APP->scene) {
APP->scene->rackScroll->reset();

// Try loading the autosave patch
if (hasAutosave()) {
try {
loadAutosave();
// Keep path and save state as it was stored in patch.json
}
catch (Exception& e) {
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what());
}
return;
}

// Try loading the template patch
loadTemplate();
}


void PatchManager::clear() {
path = "";
if (APP->scene) {
APP->scene->rack->clear();
APP->scene->rackScroll->reset();
}
if (APP->history) {
APP->history->clear();
}
APP->engine->clear();
reset();
}


@@ -83,15 +101,18 @@ void PatchManager::saveDialog() {
return;
}

// Note: If save() fails below, this should probably be reset. But we need it so toJson() doesn't set the "unsaved" property.
APP->history->setSaved();
this->path = path;

try {
save(path);
}
catch (Exception& e) {
WARN("Could not save patch: %s", e.what());
std::string message = string::f("Could not save patch: %s", e.what());
osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());
return;
}

APP->history->setSaved();
}


@@ -123,16 +144,18 @@ void PatchManager::saveAsDialog() {
path += ".vcv";
}

APP->history->setSaved();
this->path = path;

try {
save(path);
}
catch (Exception& e) {
WARN("Could not save patch: %s", e.what());
std::string message = string::f("Could not save patch: %s", e.what());
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
return;
}

this->path = path;
APP->history->setSaved();
pushRecentPath(path);
}

@@ -146,7 +169,8 @@ void PatchManager::saveTemplateDialog() {
save(asset::templatePath);
}
catch (Exception& e) {
WARN("Could not save template patch: %s", e.what());
std::string message = string::f("Could not save template patch: %s", e.what());
osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());
return;
}
}
@@ -233,26 +257,24 @@ void PatchManager::load(std::string path) {


void PatchManager::loadTemplate() {
this->path = "";
APP->history->setSaved();

try {
load(asset::templatePath);
return;
}
catch (Exception& e) {
INFO("Could not load user template patch, attempting system template patch: %s", e.what());
}

try {
load(asset::system("template.vcv"));
return;
}
catch (Exception& e) {
WARN("Could not load system template patch, clearing rack: %s", e.what());
// Do nothing because it's okay for the user template to not exist.
try {
load(asset::system("template.vcv"));
}
catch (Exception& e) {
std::string message = string::f("Could not load system template patch, clearing rack: %s", e.what());
osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, message.c_str());
clear();
}
}

clear();
// load() sets the patch's original patch, but we don't want to use that.
this->path = "";
APP->history->setSaved();
}


@@ -264,24 +286,29 @@ void PatchManager::loadTemplateDialog() {
}


bool PatchManager::hasAutosave() {
std::string patchPath = system::join(asset::autosavePath, "patch.json");
INFO("Loading autosave %s", patchPath.c_str());
FILE* file = std::fopen(patchPath.c_str(), "r");
if (!file)
return false;
std::fclose(file);
return true;
}


void PatchManager::loadAutosave() {
std::string patchPath = system::join(asset::autosavePath, "patch.json");
INFO("Loading autosave %s", patchPath.c_str());
FILE* file = std::fopen(patchPath.c_str(), "r");
if (!file) {
// Exit silently
// TODO Load template without causing infinite recursion
return;
}
if (!file)
throw Exception("Could not open autosave patch %s", patchPath.c_str());
DEFER({std::fclose(file);});

json_error_t error;
json_t* rootJ = json_loadf(file, 0, &error);
if (!rootJ) {
std::string message = string::f("Failed to load patch. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
return;
}
if (!rootJ)
throw Exception("Failed to load patch. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
DEFER({json_decref(rootJ);});

fromJson(rootJ);
@@ -293,7 +320,8 @@ void PatchManager::loadAction(std::string path) {
load(path);
}
catch (Exception& e) {
WARN("Could not load patch: %s", e.what());
std::string message = string::f("Could not load patch: %s", e.what());
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
return;
}

@@ -345,15 +373,7 @@ void PatchManager::revertDialog() {
if (!promptClear("Revert patch to the last saved state?"))
return;

try {
load(path);
}
catch (Exception& e) {
WARN("Could not load patch: %s", e.what());
return;
}

APP->history->setSaved();
loadAction(path);
}


@@ -381,6 +401,14 @@ json_t* PatchManager::toJson() {
json_t* versionJ = json_string(APP_VERSION.c_str());
json_object_set_new(rootJ, "version", versionJ);

// path
json_t* pathJ = json_string(path.c_str());
json_object_set_new(rootJ, "path", pathJ);

// unsaved
if (!APP->history->isSaved())
json_object_set_new(rootJ, "unsaved", json_boolean(true));

// Merge with rootJ
json_t* engineJ = APP->engine->toJson();
json_object_update(rootJ, engineJ);
@@ -419,6 +447,16 @@ void PatchManager::fromJson(json_t* rootJ) {
INFO("Loading patch using legacy mode %d", legacy);
}

// path
json_t* pathJ = json_object_get(rootJ, "path");
if (pathJ)
path = json_string_value(pathJ);

// unsaved
json_t* unsavedJ = json_object_get(rootJ, "unsaved");
if (!unsavedJ)
APP->history->setSaved();

APP->engine->fromJson(rootJ);
if (APP->scene) {
APP->scene->rack->fromJson(rootJ);


+ 0
- 7
src/settings.cpp View File

@@ -39,7 +39,6 @@ bool lockModules = false;
#endif
float autosaveInterval = 15.0;
bool skipLoadOnLaunch = false;
std::string patchPath;
std::list<std::string> recentPatchPaths;
std::vector<NVGcolor> cableColors = {
color::fromHexString("#fc2d5aff"), // red
@@ -111,8 +110,6 @@ json_t* toJson() {
if (skipLoadOnLaunch)
json_object_set_new(rootJ, "skipLoadOnLaunch", json_boolean(true));

json_object_set_new(rootJ, "patchPath", json_string(patchPath.c_str()));

json_t* recentPatchPathsJ = json_array();
for (const std::string& path : recentPatchPaths) {
json_array_append_new(recentPatchPathsJ, json_string(path.c_str()));
@@ -246,10 +243,6 @@ void fromJson(json_t* rootJ) {
if (skipLoadOnLaunchJ)
skipLoadOnLaunch = json_boolean_value(skipLoadOnLaunchJ);

json_t* patchPathJ = json_object_get(rootJ, "patchPath");
if (patchPathJ)
patchPath = json_string_value(patchPathJ);

recentPatchPaths.clear();
json_t* recentPatchPathsJ = json_object_get(rootJ, "recentPatchPaths");
if (recentPatchPathsJ) {


+ 2
- 9
standalone/main.cpp View File

@@ -204,15 +204,10 @@ int main(int argc, char* argv[]) {

// Initialize patch
if (loggerWasTruncated && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack crashed during the last session, possibly due to a buggy module in your patch. Clear your patch and start over?")) {
// This is the default state, but just call clear() to be explicit.
APP->patch->clear();
}
else if (patchPath != "") {
APP->patch->loadAction(patchPath);
// Do nothing
}
else {
APP->patch->path = settings::patchPath;
APP->patch->loadAutosave();
APP->patch->launch(patchPath);
}

// Run context
@@ -233,8 +228,6 @@ int main(int argc, char* argv[]) {
// Destroy context
if (!settings::headless) {
APP->patch->saveAutosave();
// TODO If Rack crashes, the settings' patch path won't be changed although the autosave will. This could possibly cause the user to overwrite their old patch with the unrelated autosave.
settings::patchPath = APP->patch->path;
}
INFO("Destroying context");
delete APP;


Loading…
Cancel
Save