Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save preferences periodically if they are modified (fix #4154) #4164

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/app/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,15 @@ namespace {
CloseMainWindow(std::unique_ptr<MainWindow>& win) : m_win(win) { }
~CloseMainWindow() { m_win.reset(nullptr); }
};
// Each 10 seconds we save the modified preferences
struct SavePreferencesPeriodically {
ui::Timer m_timer;
SavePreferencesPeriodically() : m_timer(10000) {
m_timer.Tick.connect([]{ Preferences::instance().save(); });
}
~SavePreferencesPeriodically() { }
void start() { m_timer.start(); }
};
#endif

struct CloseAllDocs {
Expand Down Expand Up @@ -466,6 +475,7 @@ void App::run()
{
#ifdef ENABLE_UI
CloseMainWindow closeMainWindow(m_mainWindow);
SavePreferencesPeriodically savePrefTimer;
#endif
CloseAllDocs closeAllDocsAtExit(context());

Expand Down Expand Up @@ -543,6 +553,8 @@ void App::run()

// Run the GUI main message loop
try {
savePrefTimer.start();

manager->run();
set_app_state(AppState::kClosing);
}
Expand Down
15 changes: 15 additions & 0 deletions src/cfg/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,32 @@ class CfgFile::CfgFileImpl {
}

void setValue(const char* section, const char* name, const char* value) {
m_dirty = true;
m_ini.SetValue(section, name, value);
}

void setBoolValue(const char* section, const char* name, bool value) {
m_dirty = true;
m_ini.SetBoolValue(section, name, value);
}

void setIntValue(const char* section, const char* name, int value) {
m_dirty = true;
m_ini.SetLongValue(section, name, value);
}

void setDoubleValue(const char* section, const char* name, double value) {
m_dirty = true;
m_ini.SetDoubleValue(section, name, value);
}

void deleteValue(const char* section, const char* name) {
m_dirty = true;
m_ini.Delete(section, name, true);
}

void deleteSection(const char* section) {
m_dirty = true;
m_ini.Delete(section, nullptr, true);
}

Expand All @@ -101,23 +107,32 @@ class CfgFile::CfgFileImpl {
return false;
}
}

m_dirty = false;
return true;
}

void save() {
if (!m_dirty)
return;

base::FileHandle file(base::open_file(m_filename, "wb"));
if (file) {
SI_Error err = m_ini.SaveFile(file.get());
if (err != SI_OK) {
LOG(ERROR, "CFG: Error %d saving configuration into %s\n",
(int)err, m_filename.c_str());
}
else {
m_dirty = false;
}
}
}

private:
std::string m_filename;
CSimpleIniA m_ini;
bool m_dirty = false;
};

CfgFile::CfgFile()
Expand Down
32 changes: 31 additions & 1 deletion src/gen/pref_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static void print_pref_class_def(TiXmlElement* elem, const std::string& classNam
std::cout
<< indent << " void load();\n"
<< indent << " void save();\n"
<< indent << " bool isDirty() const;\n"
<< indent << " Section* section(const char* id) override;\n"
<< indent << " OptionBase* option(const char* id) override;\n";

Expand Down Expand Up @@ -200,7 +201,9 @@ static void print_pref_class_impl(TiXmlElement* elem, const std::string& prefix,

std::cout
<< "void " << prefix << className << "::save()\n"
<< "{\n";
<< "{\n"
<< " if (!isDirty())\n"
<< " return;\n";

child = (elem->FirstChild() ? elem->FirstChild()->ToElement(): NULL);
while (child) {
Expand All @@ -222,6 +225,33 @@ static void print_pref_class_impl(TiXmlElement* elem, const std::string& prefix,
<< "}\n"
<< "\n";

// Section::isDirty()

std::cout
<< "bool " << prefix << className << "::isDirty() const\n"
<< "{\n";

child = (elem->FirstChild() ? elem->FirstChild()->ToElement(): NULL);
while (child) {
if (child->Value()) {
std::string name = child->Value();
if (name == "option") {
std::string memberName = convert_xmlid_to_cppid(child->Attribute("id"), false);
std::cout << " if (" << memberName << ".isDirty()) return true;\n";
}
else if (name == "section") {
std::string memberName = convert_xmlid_to_cppid(child->Attribute("id"), false);
std::cout << " if (" << memberName << ".isDirty()) return true;\n";
}
}
child = child->NextSiblingElement();
}

std::cout
<< " return false;\n"
<< "}\n"
<< "\n";

// Section::section(id)

std::cout
Expand Down