Cached joystick config loading.
Avoid parsing all the joystick configs every launch.
This commit is contained in:
parent
666a68c742
commit
6e7ac46751
5 changed files with 115 additions and 47 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 << '"');
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue