1
0
Fork 0

Cached joystick config loading.

Avoid parsing all the joystick configs every launch.
This commit is contained in:
James Turner 2012-09-21 10:17:16 +01:00
parent 666a68c742
commit 6e7ac46751
5 changed files with 115 additions and 47 deletions

View file

@ -28,55 +28,113 @@
#include "FGDeviceConfigurationMap.hxx"
#include <boost/foreach.hpp>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
#include <Main/globals.hxx>
#include <Navaids/NavDataCache.hxx>
using simgear::PropertyList;
using std::string;
FGDeviceConfigurationMap::FGDeviceConfigurationMap( const char * relative_path, SGPropertyNode_ptr aBase, const char * aChildname ) :
base(aBase),
childname(aChildname)
FGDeviceConfigurationMap::FGDeviceConfigurationMap( const string& relative_path)
{
int index = 1000;
scan_dir( SGPath(globals->get_fg_home(), relative_path), &index);
scan_dir( SGPath(globals->get_fg_root(), relative_path), &index);
PropertyList childNodes = base->getChildren(childname);
for (int k = (int)childNodes.size() - 1; k >= 0; k--) {
SGPropertyNode *n = childNodes[k];
PropertyList names = n->getChildren("name");
if (names.size() ) // && (n->getChildren("axis").size() || n->getChildren("button").size()))
for (unsigned int j = 0; j < names.size(); j++)
(*this)[names[j]->getStringValue()] = n;
}
scan_dir( SGPath(globals->get_fg_home(), relative_path));
scan_dir( SGPath(globals->get_fg_root(), relative_path));
}
FGDeviceConfigurationMap::~FGDeviceConfigurationMap()
{
// Ensure that the children don't hang around when deleted, as if
// re-created, we need to ensure that the set of names doesn't contain
// any unexpected history.
base->removeChildren( childname, false );
}
void FGDeviceConfigurationMap::scan_dir(const SGPath & path, int *index)
SGPropertyNode_ptr
FGDeviceConfigurationMap::configurationForDeviceName(const std::string& name)
{
NamePathMap::iterator it = namePathMap.find(name);
if (it == namePathMap.end()) {
return SGPropertyNode_ptr();
}
SGPropertyNode_ptr result(new SGPropertyNode);
try {
readProperties(it->second.str(), result);
result->setStringValue("source", it->second.c_str());
} catch (sg_exception& e) {
SG_LOG(SG_INPUT, SG_WARN, "parse failure reading:" << it->second);
return NULL;
}
return result;
}
bool FGDeviceConfigurationMap::hasConfiguration(const std::string& name) const
{
return namePathMap.find(name) != namePathMap.end();
}
void FGDeviceConfigurationMap::scan_dir(const SGPath & path)
{
if (!path.exists())
return;
simgear::Dir dir(path);
simgear::PathList children = dir.children(simgear::Dir::TYPE_FILE |
simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT);
for (unsigned int c=0; c<children.size(); ++c) {
SGPath path(children[c]);
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
BOOST_FOREACH(SGPath path, children) {
if (path.isDir()) {
scan_dir(path, index);
scan_dir(path);
} else if (path.extension() == "xml") {
SG_LOG(SG_INPUT, SG_DEBUG, "Reading joystick file " << path.str());
SGPropertyNode_ptr n = base->getChild(childname, (*index)++, true);
readProperties(path.str(), n);
n->setStringValue("source", path.c_str());
}
}
if (cache->isCachedFileModified(path)) {
refreshCacheForFile(path);
} else {
readCachedData(path);
} // of cached file stamp is valid
} // of child is a file with '.xml' extension
} // of directory children iteration
}
void FGDeviceConfigurationMap::readCachedData(const SGPath& path)
{
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
NamePathMap::iterator it;
BOOST_FOREACH(string s, cache->readStringListProperty(path.str())) {
// important - only insert if not already present. This ensures
// user configs can override those in the base package, since they are
// searched first.
it = namePathMap.find(s);
if (it == namePathMap.end()) {
namePathMap.insert(std::make_pair(s, path));
}
} // of cached names iteration
}
void FGDeviceConfigurationMap::refreshCacheForFile(const SGPath& path)
{
SG_LOG(SG_INPUT, SG_DEBUG, "Reading joystick file " << path.str());
SGPropertyNode_ptr n(new SGPropertyNode);
try {
readProperties(path.str(), n);
} catch (sg_exception& e) {
SG_LOG(SG_INPUT, SG_WARN, "parse failure reading:" << path);
return;
}
NamePathMap::iterator it;
string_list names;
BOOST_FOREACH(SGPropertyNode* nameProp, n->getChildren("name")) {
names.push_back(nameProp->getStringValue());
// same comment as readCachedData: only insert if not already present
it = namePathMap.find(names.back());
if (it == namePathMap.end()) {
namePathMap.insert(std::make_pair(names.back(), path));
}
}
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
cache->stampCacheFile(path);
cache->writeStringListProperty(path.str(), names);
}

View file

@ -30,19 +30,28 @@
#endif
#include <simgear/props/props.hxx>
#include <simgear/misc/sg_path.hxx>
#include <map>
class SGPath;
class FGDeviceConfigurationMap : public std::map<std::string,SGPropertyNode_ptr> {
class FGDeviceConfigurationMap
{
public:
FGDeviceConfigurationMap ( const char * relative_path, SGPropertyNode_ptr base, const char * childname );
FGDeviceConfigurationMap ( const std::string& relative_path);
virtual ~FGDeviceConfigurationMap();
SGPropertyNode_ptr configurationForDeviceName(const std::string& name);
bool hasConfiguration(const std::string& name) const;
private:
void scan_dir(const SGPath & path, int *index);
SGPropertyNode_ptr base;
const char * childname;
void scan_dir(const SGPath & path);
void readCachedData(const SGPath& path);
void refreshCacheForFile(const SGPath& path);
typedef std::map<std::string, SGPath> NamePathMap;
// mapping from joystick name to XML configuration file path
NamePathMap namePathMap;
};
#endif

View file

@ -294,7 +294,7 @@ void FGInputDevice::SetName( string name )
const char * FGEventInput::PROPERTY_ROOT = "/input/event";
FGEventInput::FGEventInput() :
configMap( "Input/Event", fgGetNode( PROPERTY_ROOT, true ), "device-named" )
configMap( "Input/Event")
{
}
@ -329,7 +329,7 @@ unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice )
SGPropertyNode_ptr deviceNode = NULL;
// look for configuration in the device map
if( configMap.count( inputDevice->GetName() ) > 0 ) {
if ( configMap.hasConfiguration( inputDevice->GetName() ) ) {
// found - copy to /input/event/device[n]
// find a free index
@ -347,7 +347,7 @@ unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice )
deviceNode = baseNode->getNode( "device", index, true );
// and copy the properties from the configuration tree
copyProperties( configMap[ inputDevice->GetName() ], deviceNode );
copyProperties( configMap.configurationForDeviceName(inputDevice->GetName()), deviceNode );
}

View file

@ -91,7 +91,7 @@ void FGJoystickInput::_remove(bool all)
for (int i = 0; i < MAX_JOYSTICKS; i++)
{
// do not remove predefined joysticks info on reinit
if ((all)||(!bindings[i].predefined))
if (all || (!bindings[i].predefined))
js_nodes->removeChild("js", i, false);
if (bindings[i].js)
delete bindings[i].js;
@ -106,7 +106,7 @@ void FGJoystickInput::init()
SGPropertyNode_ptr js_nodes = fgGetNode("/input/joysticks", true);
status_node = fgGetNode("/devices/status/joysticks", true);
FGDeviceConfigurationMap configMap("Input/Joysticks", js_nodes, "js-named");
FGDeviceConfigurationMap configMap("Input/Joysticks");
for (int i = 0; i < MAX_JOYSTICKS; i++) {
jsJoystick * js = new jsJoystick(i);
@ -128,11 +128,12 @@ void FGJoystickInput::init()
SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \"" << name << '"');
SGPropertyNode_ptr named;
if ((named = configMap[name])) {
if (configMap.hasConfiguration(name)) {
named = configMap.configurationForDeviceName(name);
string source = named->getStringValue("source", "user defined");
SG_LOG(SG_INPUT, SG_INFO, "... found joystick: " << source);
} else if ((named = configMap["default"])) {
} else if ((named = configMap.configurationForDeviceName("default"))) {
string source = named->getStringValue("source", "user defined");
SG_LOG(SG_INPUT, SG_INFO, "No config found for joystick \"" << name
<< "\"\nUsing default: \"" << source << '"');

View file

@ -423,7 +423,7 @@ public:
void prepareQueries()
{
clearProperty = prepare("DELETE FROM properties WHERE key=?1");
writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?,?)");
writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?1,?2)");
#define POSITIONED_COLS "rowid, type, ident, name, airport, lon, lat, elev_m, octree_node"
#define AND_TYPED "AND type>=?2 AND type <=?3"
@ -1064,7 +1064,7 @@ string_list NavDataCache::readStringListProperty(const string& key)
sqlite_bind_stdstring(d->readPropertyQuery, 1, key);
string_list result;
while (d->stepSelect(d->readPropertyQuery)) {
result.push_back((char*) sqlite3_column_text(d->readPropertyQuery, 1));
result.push_back((char*) sqlite3_column_text(d->readPropertyQuery, 0));
}
return result;
@ -1076,9 +1076,9 @@ void NavDataCache::writeStringListProperty(const string& key, const string_list&
sqlite_bind_stdstring(d->clearProperty, 1, key);
d->execUpdate(d->clearProperty);
sqlite_bind_stdstring(d->writePropertyMulti, 1, key);
BOOST_FOREACH(string value, values) {
d->reset(d->writePropertyMulti);
sqlite_bind_stdstring(d->writePropertyMulti, 1, key);
sqlite_bind_stdstring(d->writePropertyMulti, 2, value);
d->execInsert(d->writePropertyMulti);
}