]> git.mxchange.org Git - flightgear.git/commitdiff
Cached joystick config loading.
authorJames Turner <zakalawe@mac.com>
Fri, 21 Sep 2012 09:17:16 +0000 (10:17 +0100)
committerJames Turner <zakalawe@mac.com>
Fri, 21 Sep 2012 09:17:16 +0000 (10:17 +0100)
Avoid parsing all the joystick configs every launch.

src/Input/FGDeviceConfigurationMap.cxx
src/Input/FGDeviceConfigurationMap.hxx
src/Input/FGEventInput.cxx
src/Input/FGJoystickInput.cxx
src/Navaids/NavDataCache.cxx

index b4b6b1baf24d278812efb5990cc3df4e7f0f8bce..b27d6816cf96f4210b0147d138eb9617eb13f4e8 100644 (file)
 
 #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);
+  scan_dir( SGPath(globals->get_fg_home(), relative_path));
+  scan_dir( SGPath(globals->get_fg_root(), relative_path));
+}
 
-  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;
+FGDeviceConfigurationMap::~FGDeviceConfigurationMap()
+{
+}
+
+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;
 }
 
-FGDeviceConfigurationMap::~FGDeviceConfigurationMap()
+bool FGDeviceConfigurationMap::hasConfiguration(const std::string& name) const
 {
-  // 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 );
+  return namePathMap.find(name) != namePathMap.end();
 }
 
-void FGDeviceConfigurationMap::scan_dir(const SGPath & path, int *index)
+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);
+}
index 6a6aceae3306582e11c44266287ba201ff938689..283973d281bce833ebf1f63a587db4acca28dcd7 100644 (file)
 #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
index 4a53a63d0a04ca1dd6ab2bec161d0061797cbbac..a6db87b3167280b36ad17fe331e72459085c7477 100644 (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 );
 
   }
 
index 046106abe9323ad4e77bd0ec73ace5f8c6572a47..e9ecc33eec5662a9dd23655502caa265972e18e0 100644 (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 << '"');
index 3506d64fe13d86f80f979bc502e3e1d89c714eb2..5737b7972d3f04635c16285a0c5654308f10b594 100644 (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);
   }