Hi,

attached are the latest versions of my options saving patches. For those who missed it (probably because they were posted in the "KLN89 GPS added" thread): they implement persistent dialog options, so changes in rendering, static LOD and sound settings dialogs are made permanent. For this I patched SimGear to allow a new attribute on property nodes (userarchive) and generalized the writeProperties, writeNode and isArchivable methods to support arbitrary archive flags. FlightGear is reading in the ~/.fgfs/preferences.xml file at startup and writes the properties to it on exit. The new function in this patch is that the directory is created if it does not exist yet. For this I added the makeDir method to SGPath.

Missing is support for Windows, where the directory should be like %PROFILE%/Application Data/FlightGear (or such). Also I don't know if Windows supports the mkdir function. Would be nice if someone could port.

Also nice would be any review of the code :) and of course some info about how the chances are for inclusion.

Tanks,
Nine
Index: simgear/misc/sg_path.cxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/misc/sg_path.cxx,v
retrieving revision 1.12
diff -u -3 -p -r1.12 sg_path.cxx
--- simgear/misc/sg_path.cxx	19 Nov 2004 21:44:16 -0000	1.12
+++ simgear/misc/sg_path.cxx	16 Dec 2005 23:03:26 -0000
@@ -26,7 +26,10 @@
 #include <simgear/compiler.h>
 
 #include <simgear_config.h>
+#include <simgear/debug/logstream.hxx>
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "sg_path.hxx"
 
@@ -183,6 +186,12 @@ bool SGPath::exists() const {
 }
 
 
+void SGPath::makeDir( __mode_t mode ) {
+    if ( mkdir( dir().c_str(), mode ) ) {
+	    SG_LOG( SG_IO, SG_ALERT, "Error creating directory: " + dir() );
+    }
+}
+
 string_list sgPathSplit( const string &search_path ) {
     string tmp = search_path;
     string_list result;
Index: simgear/misc/sg_path.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/misc/sg_path.hxx,v
retrieving revision 1.7
diff -u -3 -p -r1.7 sg_path.hxx
--- simgear/misc/sg_path.hxx	19 Nov 2004 21:44:16 -0000	1.7
+++ simgear/misc/sg_path.hxx	16 Dec 2005 23:03:26 -0000
@@ -132,6 +132,11 @@ public:
      */
     bool exists() const;
 
+    /**
+     * Create the designated directory.
+     */
+    void makedir(__mode_t mode);
+
 private:
 
     void fix();
Index: simgear/props/props.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/props/props.hxx,v
retrieving revision 1.14
diff -u -3 -p -r1.14 props.hxx
--- simgear/props/props.hxx	23 Oct 2005 11:55:48 -0000	1.14
+++ simgear/props/props.hxx	16 Dec 2005 23:03:26 -0000
@@ -585,7 +585,8 @@ public:
     ARCHIVE = 4,
     REMOVED = 8,
     TRACE_READ = 16,
-    TRACE_WRITE = 32
+    TRACE_WRITE = 32,
+    USERARCHIVE = 64
   };
 
 
Index: simgear/props/props_io.cxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/props/props_io.cxx,v
retrieving revision 1.10
diff -u -3 -p -r1.10 props_io.cxx
--- simgear/props/props_io.cxx	28 Jun 2005 11:19:41 -0000	1.10
+++ simgear/props/props_io.cxx	16 Dec 2005 23:03:26 -0000
@@ -37,8 +37,8 @@ class PropsVisitor : public XMLVisitor
 {
 public:
 
-  PropsVisitor (SGPropertyNode * root, const string &base)
-    : _root(root), _level(0), _base(base), _hasException(false) {}
+  PropsVisitor (SGPropertyNode * root, const string &base, int default_mode = 0)
+    : _root(root), _level(0), _base(base), _hasException(false), _default_mode(default_mode) {}
 
   virtual ~PropsVisitor () {}
 
@@ -85,6 +85,7 @@ private:
     _level--;
   }
 
+  int _default_mode;
   string _data;
   SGPropertyNode * _root;
   int _level;
@@ -177,7 +178,7 @@ PropsVisitor::startElement (const char *
 				// Get the access-mode attributes,
 				// but don't set yet (in case they
 				// prevent us from recording the value).
-    int mode = 0;
+    int mode = _default_mode;
 
     attval = atts.getValue("read");
     if (checkFlag(attval, true))
@@ -194,6 +195,9 @@ PropsVisitor::startElement (const char *
     attval = atts.getValue("trace-write");
     if (checkFlag(attval, false))
       mode |= SGPropertyNode::TRACE_WRITE;
+    attval = atts.getValue("userarchive");
+    if (checkFlag(attval, false))
+      mode |= SGPropertyNode::USERARCHIVE;
 
 				// Check for an alias.
     attval = atts.getValue("alias");
@@ -299,9 +303,9 @@ PropsVisitor::warning (const char * mess
  */
 void
 readProperties (istream &input, SGPropertyNode * start_node,
-		const string &base)
+		const string &base, int default_mode)
 {
-  PropsVisitor visitor(start_node, base);
+  PropsVisitor visitor(start_node, base, default_mode);
   readXML(input, visitor, base);
   if (visitor.hasException())
     throw visitor.getException();
@@ -316,9 +320,10 @@ readProperties (istream &input, SGProper
  * @return true if the read succeeded, false otherwise.
  */
 void
-readProperties (const string &file, SGPropertyNode * start_node)
+readProperties (const string &file, SGPropertyNode * start_node,
+                int default_mode)
 {
-  PropsVisitor visitor(start_node, file);
+  PropsVisitor visitor(start_node, file, default_mode);
   readXML(file, visitor);
   if (visitor.hasException())
     throw visitor.getException();
@@ -334,9 +339,9 @@ readProperties (const string &file, SGPr
  * @return true if the read succeeded, false otherwise.
  */
 void readProperties (const char *buf, const int size,
-                     SGPropertyNode * start_node)
+                     SGPropertyNode * start_node, int default_mode)
 {
-  PropsVisitor visitor(start_node, "");
+  PropsVisitor visitor(start_node, "", default_mode);
   readXML(buf, size, visitor);
   if (visitor.hasException())
     throw visitor.getException();
@@ -439,15 +444,15 @@ writeAtts (ostream &output, const SGProp
  * Test whether a node is archivable or has archivable descendants.
  */
 static bool
-isArchivable (const SGPropertyNode * node)
+isArchivable (const SGPropertyNode * node, SGPropertyNode::Attribute archive_flag)
 {
   // FIXME: it's inefficient to do this all the time
-  if (node->getAttribute(SGPropertyNode::ARCHIVE))
+  if (node->getAttribute(archive_flag))
     return true;
   else {
     int nChildren = node->nChildren();
     for (int i = 0; i < nChildren; i++)
-      if (isArchivable(node->getChild(i)))
+      if (isArchivable(node->getChild(i), archive_flag))
 	return true;
   }
   return false;
@@ -456,12 +461,12 @@ isArchivable (const SGPropertyNode * nod
 
 static bool
 writeNode (ostream &output, const SGPropertyNode * node,
-	   bool write_all, int indent)
+           bool write_all, int indent, SGPropertyNode::Attribute archive_flag)
 {
 				// Don't write the node or any of
 				// its descendants unless it is
 				// allowed to be archived.
-  if (!write_all && !isArchivable(node))
+  if (!write_all && !isArchivable(node, archive_flag))
     return true;		// Everything's OK, but we won't write.
 
   const string name = node->getName();
@@ -469,7 +474,7 @@ writeNode (ostream &output, const SGProp
 
 				// If there is a literal value,
 				// write it first.
-  if (node->hasValue() && (write_all || node->getAttribute(SGPropertyNode::ARCHIVE))) {
+  if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
     doIndent(output, indent);
     output << '<' << name;
     writeAtts(output, node);
@@ -492,7 +497,7 @@ writeNode (ostream &output, const SGProp
     writeAtts(output, node);
     output << '>' << endl;
     for (int i = 0; i < nChildren; i++)
-      writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP);
+      writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag);
     doIndent(output, indent);
     output << "</" << name << '>' << endl;
   }
@@ -503,7 +508,7 @@ writeNode (ostream &output, const SGProp
 
 void
 writeProperties (ostream &output, const SGPropertyNode * start_node,
-		 bool write_all)
+                 bool write_all, SGPropertyNode::Attribute archive_flag)
 {
   int nChildren = start_node->nChildren();
 
@@ -511,7 +516,7 @@ writeProperties (ostream &output, const 
   output << "<PropertyList>" << endl;
 
   for (int i = 0; i < nChildren; i++) {
-    writeNode(output, start_node->getChild(i), write_all, INDENT_STEP);
+    writeNode(output, start_node->getChild(i), write_all, INDENT_STEP, archive_flag);
   }
 
   output << "</PropertyList>" << endl;
@@ -520,11 +525,11 @@ writeProperties (ostream &output, const 
 
 void
 writeProperties (const string &file, const SGPropertyNode * start_node,
-		 bool write_all)
+                 bool write_all, SGPropertyNode::Attribute archive_flag)
 {
   ofstream output(file.c_str());
   if (output.good()) {
-    writeProperties(output, start_node, write_all);
+    writeProperties(output, start_node, write_all, archive_flag);
   } else {
     throw sg_io_exception("Cannot open file", sg_location(file));
   }
Index: simgear/props/props_io.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/props/props_io.hxx,v
retrieving revision 1.2
diff -u -3 -p -r1.2 props_io.hxx
--- simgear/props/props_io.hxx	10 Sep 2004 15:57:52 -0000	1.2
+++ simgear/props/props_io.hxx	16 Dec 2005 23:03:27 -0000
@@ -32,34 +32,37 @@ SG_USING_STD(ostream);
  * Read properties from an XML input stream.
  */
 void readProperties (istream &input, SGPropertyNode * start_node,
-		     const string &base = "");
+		     const string &base = "", int default_mode = 0);
 
 
 /**
  * Read properties from an XML file.
  */
-void readProperties (const string &file, SGPropertyNode * start_node);
+void readProperties (const string &file, SGPropertyNode * start_node,
+                     int default_mode = 0);
 
 
 /**
  * Read properties from an in-memory buffer.
  */
 void readProperties (const char *buf, const int size,
-                     SGPropertyNode * start_node);
+                     SGPropertyNode * start_node, int default_mode = 0);
 
 
 /**
  * Write properties to an XML output stream.
  */
 void writeProperties (ostream &output, const SGPropertyNode * start_node,
-		      bool write_all = false);
+		      bool write_all = false,
+		      SGPropertyNode::Attribute archive_flag = SGPropertyNode::ARCHIVE);
 
 
 /**
  * Write properties to an XML file.
  */
 void writeProperties (const string &file, const SGPropertyNode * start_node,
-		      bool write_all = false);
+		      bool write_all = false,
+		      SGPropertyNode::Attribute archive_flag = SGPropertyNode::ARCHIVE);
 
 
 /**
Index: src/Main/fg_commands.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/fg_commands.cxx,v
retrieving revision 1.64
diff -u -3 -p -r1.64 fg_commands.cxx
--- src/Main/fg_commands.cxx	11 Nov 2005 07:17:26 -0000	1.64
+++ src/Main/fg_commands.cxx	16 Dec 2005 22:52:35 -0000
@@ -189,9 +189,27 @@ do_nasal (const SGPropertyNode * arg)
 static bool
 do_exit (const SGPropertyNode * arg)
 {
-  SG_LOG(SG_INPUT, SG_INFO, "Program exit requested.");
-  fgExit(arg->getIntValue("status", 0));
-  return true;
+    SG_LOG(SG_INPUT, SG_INFO, "Program exit requested.");
+
+    SGPath config( globals->get_fg_root() );
+    char* envp = ::getenv( "HOME" );
+    if ( envp != NULL ) {
+        config.set( envp );
+        config.append( ".fgfs" );
+        config.append( "preferences.xml" );
+        if ( ! config.exists() )
+            config.makedir( 0700 );
+        SG_LOG(SG_IO, SG_INFO, "Saving user preferences");
+        try {
+            writeProperties(config.str(), globals->get_props(), false, SGPropertyNode::USERARCHIVE);
+        } catch (const sg_exception &e) {
+            guiErrorMessage("Error saving preferences: ", e);
+        }
+
+        SG_LOG(SG_INPUT, SG_INFO, "Finished Saving user preferences");
+    }
+    fgExit(arg->getIntValue("status", 0));
+    return true;
 }
 
 
Index: src/Main/fg_init.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/fg_init.cxx,v
retrieving revision 1.139
diff -u -3 -p -r1.139 fg_init.cxx
--- src/Main/fg_init.cxx	29 Nov 2005 03:12:24 -0000	1.139
+++ src/Main/fg_init.cxx	16 Dec 2005 22:52:36 -0000
@@ -607,6 +607,18 @@ bool fgInitConfig ( int argc, char **arg
         SG_LOG( SG_INPUT, SG_ALERT, "No default aircraft specified" );
     }
 
+    SGPath config( globals->get_fg_root() );
+
+    char* envp = ::getenv( "HOME" );
+    if ( envp != NULL ) {
+        config.set( envp );
+        config.append( ".fgfs" );
+        config.append( "preferences.xml" );
+        SG_LOG(SG_INPUT, SG_INFO, "Reading user preferences");
+        fgLoadProps(config.str().c_str(), globals->get_props(), false, SGPropertyNode::USERARCHIVE);
+        SG_LOG(SG_INPUT, SG_INFO, "Finished Reading user preferences");
+    }
+
     // parse options after loading aircraft to ensure any user
     // overrides of defaults are honored.
     do_options(argc, argv);
Index: src/Main/fg_props.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/fg_props.cxx,v
retrieving revision 1.22
diff -u -3 -p -r1.22 fg_props.cxx
--- src/Main/fg_props.cxx	17 Nov 2005 15:47:01 -0000	1.22
+++ src/Main/fg_props.cxx	16 Dec 2005 22:52:36 -0000
@@ -585,7 +585,7 @@ fgLoadFlight (istream &input)
 
 
 bool
-fgLoadProps (const char * path, SGPropertyNode * props, bool in_fg_root)
+fgLoadProps (const char * path, SGPropertyNode * props, bool in_fg_root, int default_mode)
 {
     string fullpath;
     if (in_fg_root) {
@@ -597,7 +597,7 @@ fgLoadProps (const char * path, SGProper
     }
 
     try {
-        readProperties(fullpath, props);
+        readProperties(fullpath, props, default_mode);
     } catch (const sg_exception &e) {
         guiErrorMessage("Error reading properties: ", e);
         return false;
Index: src/Main/fg_props.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/fg_props.hxx,v
retrieving revision 1.5
diff -u -3 -p -r1.5 fg_props.hxx
--- src/Main/fg_props.hxx	20 Feb 2004 17:35:33 -0000	1.5
+++ src/Main/fg_props.hxx	16 Dec 2005 22:52:37 -0000
@@ -69,7 +69,7 @@ extern bool fgLoadFlight (istream &input
  *         otherwise.
  */
 extern bool fgLoadProps (const char * path, SGPropertyNode * props,
-                         bool in_fg_root = true);
+                         bool in_fg_root = true, int default_mode = 0);
 
 
 
Index: preferences.xml
===================================================================
RCS file: /var/cvs/FlightGear-0.9/data/preferences.xml,v
retrieving revision 1.190
diff -u -3 -p -r1.190 preferences.xml
--- preferences.xml	24 Nov 2005 10:51:24 -0000	1.190
+++ preferences.xml	29 Nov 2005 23:39:16 -0000
@@ -42,20 +42,28 @@ Started September 2000 by David Megginso
    <debug type="bool">false</debug>
    <realism>5</realism>
    <static-lod>
-    <detailed>1500</detailed>
-    <rough>9000</rough>
-    <bare>30000</bare>
+    <detailed userarchive="y">1500</detailed>
+    <rough userarchive="y">9000</rough>
+    <bare userarchive="y">30000</bare>
    </static-lod>
    <random-objects type="bool">true</random-objects>
-   <horizon-effect type="bool">false</horizon-effect>
-   <enhanced-lighting type="bool">false</enhanced-lighting>
-   <distance-attenuation type="bool">false</distance-attenuation>
+   <horizon-effect type="bool" userarchive="y">false</horizon-effect>
+   <enhanced-lighting type="bool" userarchive="y">false</enhanced-lighting>
+   <distance-attenuation type="bool" userarchive="y">false</distance-attenuation>
+   <precipitation-enable type="bool" userarchive="y">false</precipitation-enable>
+   <lightning-enable type="bool" userarchive="y">false</lightning-enable>
+   <bump-mapping type="bool" userarchive="y">false</bump-mapping>
+   <clouds3d-enable type="bool" userarchive="y">false</clouds3d-enable>
+   <clouds3d-vis-range type="float" userarchive="y">25000</clouds3d-vis-range>
+   <clouds3d-density type="float" userarchive="y">100</clouds3d-density>
+   <clouds3d-cache-size type="int" userarchive="y">1024</clouds3d-cache-size>
+   <clouds3d-cache-resolution type="int" userarchive="y">64</clouds3d-cache-resolution>
    <draw-otw type="bool">true</draw-otw>
-   <shadows-ac type="bool">false</shadows-ac>
-   <shadows-ac-transp type="bool">false</shadows-ac-transp>
-   <shadows-ai type="bool">false</shadows-ai>
-   <shadows-to type="bool">false</shadows-to>
-   <shadows-debug type="bool">false</shadows-debug>
+   <shadows-ac type="bool" userarchive="y">false</shadows-ac>
+   <shadows-ac-transp type="bool" userarchive="y">false</shadows-ac-transp>
+   <shadows-ai type="bool" userarchive="y">false</shadows-ai>
+   <shadows-to type="bool" userarchive="y">false</shadows-to>
+   <shadows-debug type="bool" userarchive="y">false</shadows-debug>
   </rendering>
   <model-hz type="int">120</model-hz>
   <navdb>
@@ -65,7 +73,7 @@ Started September 2000 by David Megginso
    </localizers>
   </navdb>
   <sound>
-   <volume>0.8</volume>
+   <volume userarchive="y">0.8</volume>
    <pause type="bool">false</pause>
    <voice type="bool">true</voice>
   </sound>
@@ -87,7 +95,7 @@ Started September 2000 by David Megginso
    <visibility type="bool">false</visibility>
    <antialiased type="bool">false</antialiased>
    <alpha type="float">0.67</alpha>
-   <draw-fps>false</draw-fps>
+   <draw-fps userarchive="y">false</draw-fps>
   </hud>
   <systems>
    <path>Aircraft/Generic/generic-systems.xml</path>
_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@flightgear.org
http://mail.flightgear.org/mailman/listinfo/flightgear-devel
2f585eeea02e2c79d7b1d8c4963bae2d

Reply via email to