Skip to content

Commit

Permalink
Added registry::Autosaver class to automatically persist settings whe…
Browse files Browse the repository at this point in the history
…n the XML tree has changed

Prevents losing settings or keybinds when the app is crashing or
terminated through the debugger.
  • Loading branch information
codereader committed Jul 11, 2017
1 parent 4e01460 commit 8ee895d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 1 deletion.
45 changes: 45 additions & 0 deletions plugins/xmlregistry/Autosaver.h
@@ -0,0 +1,45 @@
#pragma once

#include <functional>
#include <wx/event.h>
#include <wx/app.h>
#include "itextstream.h"
#include "iregistry.h"

namespace registry
{

class Autosaver :
public wxEvtHandler
{
private:
std::function<bool()> _shouldSave;

public:
Autosaver(const std::function<bool()>& shouldSaveCallback) :
_shouldSave(shouldSaveCallback)
{
wxTheApp->Connect(wxEVT_IDLE, wxIdleEventHandler(Autosaver::onIdle), nullptr, this);
}

~Autosaver()
{
wxTheApp->Disconnect(wxEVT_IDLE, wxIdleEventHandler(Autosaver::onIdle), nullptr, this);
}

private:
void onIdle(wxIdleEvent& ev)
{
if (_shouldSave())
{
rMessage() << "Auto-saving registry to user settings path." << std::endl;

if (module::GlobalModuleRegistry().moduleExists(MODULE_XMLREGISTRY))
{
GlobalRegistry().saveToDisk();
}
}
}
};

}
2 changes: 1 addition & 1 deletion plugins/xmlregistry/RegistryTree.cpp
Expand Up @@ -300,7 +300,7 @@ void RegistryTree::exportToFile(const std::string& key, const std::string& filen
// Save the whole document to the specified filename
targetDoc.saveToFile(filename);

rMessage() << "XMLRegistry: Saved " << key << " to " << filename << std::endl;
// rMessage() << "XMLRegistry: Saved " << key << " to " << filename << std::endl;
}

void RegistryTree::dump() const
Expand Down
24 changes: 24 additions & 0 deletions plugins/xmlregistry/XMLRegistry.cpp
Expand Up @@ -13,6 +13,7 @@

XMLRegistry::XMLRegistry() :
_queryCounter(0),
_changesSinceLastSave(0),
_shutdown(false)
{}

Expand All @@ -23,6 +24,7 @@ void XMLRegistry::shutdown()
saveToDisk();

_shutdown = true;
_autosaver.reset();
}

void XMLRegistry::saveToDisk()
Expand Down Expand Up @@ -72,6 +74,8 @@ void XMLRegistry::saveToDisk()

// Save the remaining /darkradiant/user tree to user.xml so that the current settings are preserved
copiedTree.exportToFile("user", settingsPath + "user.xml");

_changesSinceLastSave = 0;
}

xml::NodeList XMLRegistry::findXPath(const std::string& path)
Expand Down Expand Up @@ -121,6 +125,11 @@ void XMLRegistry::deleteXPath(const std::string& path)
// Add the toplevel node to the path if required
xml::NodeList nodeList = findXPath(path);

if (!nodeList.empty())
{
_changesSinceLastSave++;
}

for (xml::Node& node : nodeList)
{
// unlink and delete the node
Expand All @@ -134,6 +143,8 @@ xml::Node XMLRegistry::createKeyWithName(const std::string& path,
{
assert(!_shutdown);

_changesSinceLastSave++;

// The key will be created in the user tree (the default tree is read-only)
return _userTree.createKeyWithName(path, key, name);
}
Expand All @@ -142,6 +153,8 @@ xml::Node XMLRegistry::createKey(const std::string& key)
{
assert(!_shutdown);

_changesSinceLastSave++;

return _userTree.createKey(key);
}

Expand All @@ -150,6 +163,8 @@ void XMLRegistry::setAttribute(const std::string& path,
{
assert(!_shutdown);

_changesSinceLastSave++;

_userTree.setAttribute(path, attrName, attrValue);
}

Expand Down Expand Up @@ -192,6 +207,8 @@ void XMLRegistry::set(const std::string& key, const std::string& value)
// Convert the string to UTF-8 before storing it into the RegistryTree
_userTree.set(key, wxutil::IConv::localeToUTF8(value));

_changesSinceLastSave++;

// Notify the observers
emitSignalForKey(key);
}
Expand All @@ -209,6 +226,8 @@ void XMLRegistry::import(const std::string& importFilePath, const std::string& p
_standardTree.importFromFile(importFilePath, parentKey);
break;
}

_changesSinceLastSave++;
}

void XMLRegistry::emitSignalForKey(const std::string& changedKey)
Expand Down Expand Up @@ -294,4 +313,9 @@ void XMLRegistry::initialiseModule(const ApplicationContext& ctx)
// Subscribe to the post-module-shutdown signal to save changes to disk
module::GlobalModuleRegistry().signal_allModulesUninitialised().connect(
sigc::mem_fun(this, &XMLRegistry::shutdown));

_autosaver.reset(new registry::Autosaver([this]()
{
return _changesSinceLastSave > 0;
}));
}
7 changes: 7 additions & 0 deletions plugins/xmlregistry/XMLRegistry.h
Expand Up @@ -26,6 +26,7 @@

#include "imodule.h"
#include "RegistryTree.h"
#include "Autosaver.h"

class XMLRegistry :
public Registry
Expand All @@ -46,11 +47,17 @@ class XMLRegistry :
// The query counter for some statistics :)
unsigned int _queryCounter;

// Change tracking counter, is reset when saveToDisk() is called
unsigned int _changesSinceLastSave;

// TRUE if the registry has already been saved to disk
// At this point no more write operations should be made
// to the registry
bool _shutdown;

// The autosaver
std::unique_ptr<registry::Autosaver> _autosaver;

public:
/* Constructor:
* Creates two empty RegistryTrees in the memory with the default toplevel node
Expand Down
1 change: 1 addition & 0 deletions tools/msvc2015/xmlregistry.vcxproj
Expand Up @@ -320,6 +320,7 @@
<ClCompile Include="..\..\plugins\xmlregistry\XMLRegistryModule.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\plugins\xmlregistry\Autosaver.h" />
<ClInclude Include="..\..\plugins\xmlregistry\RegistryTree.h" />
<ClInclude Include="..\..\plugins\xmlregistry\XMLRegistry.h" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions tools/msvc2015/xmlregistry.vcxproj.filters
Expand Up @@ -24,5 +24,8 @@
<ClInclude Include="..\..\plugins\xmlregistry\XMLRegistry.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\..\plugins\xmlregistry\Autosaver.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
</Project>

0 comments on commit 8ee895d

Please sign in to comment.