#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
+#include <simgear/misc/interpolator.hxx>
+#include <simgear/io/HTTPRequest.hxx>
#include <Cockpit/panel.hxx>
#include <Cockpit/panel_io.hxx>
#include <ATC/CommStation.hxx>
#include <Navaids/navrecord.hxx>
#include <Navaids/navlist.hxx>
+#include <Network/HTTPClient.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"
#include <Main/viewer.hxx>
#include <Environment/presets.hxx>
+#include <boost/scoped_array.hpp>
+
using std::string;
using std::ifstream;
using std::ofstream;
{
SG_LOG(SG_INPUT, SG_INFO, "Program exit requested.");
fgSetBool("/sim/signals/exit", true);
-
- if (fgGetBool("/sim/startup/save-on-exit")) {
-#ifdef _WIN32
- char* envp = ::getenv( "APPDATA" );
- if ( envp != NULL ) {
- SGPath config( envp );
- config.append( "flightgear.org" );
-#else
- if ( homedir != NULL ) {
- SGPath config( homedir );
- config.append( ".fgfs" );
-#endif
- config.append( "autosave.xml" );
- config.create_dir( 0700 );
- SG_LOG(SG_IO, SG_INFO, "Saving user settings to " << config.str());
- try {
- writeProperties(config.str(), globals->get_props(), false, SGPropertyNode::USERARCHIVE);
- } catch (const sg_exception &e) {
- guiErrorMessage("Error writing autosave.xml: ", e);
- }
-
- SG_LOG(SG_INPUT, SG_DEBUG, "Finished Saving user settings");
- }
- }
-
+ globals->saveUserSettings();
fgOSExit(arg->getIntValue("status", 0));
return true;
}
}
SG_LOG(SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path);
globals->get_current_panel()->unbind();
- delete globals->get_current_panel();
globals->set_current_panel( new_panel );
globals->get_current_panel()->bind();
return true;
return true;
}
+/**
+ * Built-in command: interpolate a property value over time
+ *
+ * property: the name of the property value to interpolate.
+ * value[0..n] any number of constant values to interpolate
+ * time[0..n] time between each value, number of time elements must
+ * match those of value elements
+ * -or-
+ * property[1..n] any number of target values taken from named properties
+ * time[0..n] time between each value, number of time elements must
+ * match those of property elements minus one
+ */
+static bool
+do_property_interpolate (const SGPropertyNode * arg)
+{
+ SGPropertyNode * prop = get_prop(arg);
+
+ simgear::PropertyList valueNodes = arg->getChildren( "value" );
+ simgear::PropertyList timeNodes = arg->getChildren( "time" );
+
+ boost::scoped_array<double> value;
+ boost::scoped_array<double> time;
+
+ if( valueNodes.size() > 0 ) {
+ // must match
+ if( timeNodes.size() != valueNodes.size() )
+ return false;
+
+ value.reset( new double[valueNodes.size()] );
+ for( simgear::PropertyList::size_type n = 0; n < valueNodes.size(); n++ ) {
+ value[n] = valueNodes[n]->getDoubleValue();
+ }
+ } else {
+ valueNodes = arg->getChildren("property");
+ // must have one more property node
+ if( valueNodes.size() - 1 != timeNodes.size() )
+ return false;
+
+ value.reset( new double[valueNodes.size()-1] );
+ for( simgear::PropertyList::size_type n = 0; n < valueNodes.size()-1; n++ ) {
+ value[n] = fgGetNode(valueNodes[n+1]->getStringValue(), "/null")->getDoubleValue();
+ }
+
+ }
+
+ time.reset( new double[timeNodes.size()] );
+ for( simgear::PropertyList::size_type n = 0; n < timeNodes.size(); n++ ) {
+ time[n] = timeNodes[n]->getDoubleValue();
+ }
+
+ ((SGInterpolator*)globals->get_subsystem_mgr()
+ ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
+ ->interpolate(prop, timeNodes.size(), value.get(), time.get() );
+
+ return true;
+}
/**
* Built-in command: reinit the data logging system based on the
}
}
+static bool
+do_open_browser (const SGPropertyNode * arg)
+{
+ string path;
+ if (arg->hasValue("path"))
+ path = arg->getStringValue("path");
+ else
+ if (arg->hasValue("url"))
+ path = arg->getStringValue("url");
+ else
+ return false;
+
+ return openBrowser(path);
+}
/**
* Apply a value in the active XML-configured dialog.
return true;
}
+class RemoteXMLRequest : public simgear::HTTP::Request
+{
+public:
+ SGPropertyNode_ptr _complete;
+ SGPropertyNode_ptr _status;
+ SGPropertyNode_ptr _failed;
+ SGPropertyNode_ptr _target;
+ string propsData;
+
+ RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) :
+ simgear::HTTP::Request(url),
+ _target(targetNode)
+ {
+ }
+
+ void setCompletionProp(SGPropertyNode_ptr p)
+ {
+ _complete = p;
+ }
+
+ void setStatusProp(SGPropertyNode_ptr p)
+ {
+ _status = p;
+ }
+
+ void setFailedProp(SGPropertyNode_ptr p)
+ {
+ _failed = p;
+ }
+protected:
+ virtual void gotBodyData(const char* s, int n)
+ {
+ propsData += string(s, n);
+ }
+
+ virtual void responseComplete()
+ {
+ int response = responseCode();
+ bool failed = false;
+ if (response == 200) {
+ try {
+ const char* buffer = propsData.c_str();
+ readProperties(buffer, propsData.size(), _target, true);
+ } catch (const sg_exception &e) {
+ SG_LOG(SG_IO, SG_WARN, "parsing XML from remote, failed: " << e.getFormattedMessage());
+ failed = true;
+ response = 406; // 'not acceptable', anything better?
+ }
+ } else {
+ failed = true;
+ }
+ // now the response data is output, signal Nasal / listeners
+ if (_complete) _complete->setBoolValue(true);
+ if (_status) _status->setIntValue(response);
+ if (_failed) _failed->setBoolValue(failed);
+ }
+};
+
+
+static bool
+do_load_xml_from_url(const SGPropertyNode * arg)
+{
+ std::string url(arg->getStringValue("url"));
+ if (url.empty())
+ return false;
+
+ SGPropertyNode *targetnode;
+ if (arg->hasValue("targetnode"))
+ targetnode = fgGetNode(arg->getStringValue("targetnode"), true);
+ else
+ targetnode = const_cast<SGPropertyNode *>(arg)->getNode("data", true);
+
+ RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
+
+// connect up optional reporting properties
+ if (arg->hasValue("complete"))
+ req->setCompletionProp(fgGetNode(arg->getStringValue("complete"), true));
+ if (arg->hasValue("failure"))
+ req->setFailedProp(fgGetNode(arg->getStringValue("failure"), true));
+ if (arg->hasValue("status"))
+ req->setStatusProp(fgGetNode(arg->getStringValue("status"), true));
+
+ FGHTTPClient::instance()->makeRequest(req);
+
+ return true;
+}
+
/**
* An fgcommand to allow saving of xml files via nasal,
{ "property-scale", do_property_scale },
{ "property-cycle", do_property_cycle },
{ "property-randomize", do_property_randomize },
+ { "property-interpolate", do_property_interpolate },
{ "data-logging-commit", do_data_logging_commit },
{ "dialog-new", do_dialog_new },
{ "dialog-show", do_dialog_show },
{ "dialog-close", do_dialog_close },
{ "dialog-update", do_dialog_update },
{ "dialog-apply", do_dialog_apply },
+ { "open-browser", do_open_browser },
{ "gui-redraw", do_gui_redraw },
{ "add-model", do_add_model },
{ "set-cursor", do_set_cursor },
*/
{ "loadxml", do_load_xml_to_proptree},
{ "savexml", do_save_xml_from_proptree },
+ { "xmlhttprequest", do_load_xml_from_url },
{ "press-cockpit-button", do_press_cockpit_button },
{ "release-cockpit-button", do_release_cockpit_button },
{ "dump-scenegraph", do_dump_scene_graph },