FlightGear next
FGQmlInstance.cxx
Go to the documentation of this file.
1#include "FGQmlInstance.hxx"
2
3#include <QDebug>
4#include <QJSValueIterator>
5
7
8#include <simgear/structure/commands.hxx>
9
10#include <Main/fg_props.hxx>
11
12namespace {
13
14void convertJSObjectToPropertyNode(QJSValue js, SGPropertyNode *node);
15
16void convertSingleJSValue(QJSValue v, SGPropertyNode* node)
17{
18 if (v.isNumber()) {
19 node->setDoubleValue(v.toNumber());
20 } else if (v.isBool()) {
21 node->setBoolValue(v.toBool());
22 } else if (v.isString()) {
23 node->setStringValue(v.toString().toStdString());
24 } else {
25 qWarning() << Q_FUNC_INFO << "unhandld JS type";
26 }
27}
28
29void convertJSObjectToPropertyNode(QJSValue js, SGPropertyNode* node)
30{
31 QJSValueIterator it(js);
32 while (it.hasNext()) {
33 it.next();
34 const auto propName = it.name().toStdString();
35 QJSValue v = it.value();
36 if (v.isObject()) {
37 // recursion is fun :)
38 SGPropertyNode_ptr childNode = node->getChild(propName, true);
39 convertJSObjectToPropertyNode(v, childNode);
40 } else if (v.isArray()) {
41 // mapping arbitrary JS arrays is slightly uncomfortable, but
42 // this makes the common case work:
43 // foobar: [1,4, "apples", false]
44 // becomes foobar[0] = 1; foobar[1] = 4; foobar[2] = "apples";
45 // foobar[3] = false;
46 // not perfect but useful enough to be worth supporting.
47 QJSValueIterator arrayIt(v);
48 int propIndex = 0;
49 while (arrayIt.hasNext()) {
50 arrayIt.next();
51 SGPropertyNode_ptr childNode = node->getChild(propName, propIndex++, true);
52 if (arrayIt.value().isArray()) {
53 // there is no sensible mapping of this to SGPropertyNode
54 qWarning() << Q_FUNC_INFO <<"arrays of array not possible";
55 } else if (arrayIt.value().isObject()) {
56 convertJSObjectToPropertyNode(arrayIt.value(), childNode);
57 } else {
58 // simple case, just convert the value in place
59 convertSingleJSValue(arrayIt.value(), childNode);
60 }
61 }
62 } else {
63 convertSingleJSValue(v, node->getChild(propName, true));
64 }
65 }
66}
67
68} // of anonymous namespace
69
70FGQmlInstance::FGQmlInstance(QObject *parent) : QObject(parent)
71{
72
73}
74
75bool FGQmlInstance::command(QString name, QJSValue args)
76{
77 const std::string cmdName = name.toStdString();
78
79 SGCommandMgr* mgr = SGCommandMgr::instance();
80 if (!mgr->getCommand(cmdName)) {
81 qWarning() << "No such command" << name;
82 return false;
83 }
84
85 SGPropertyNode_ptr propArgs(new SGPropertyNode);
86
87 // convert JSValue args into a property tree.
88 if (args.isObject()) {
89 convertJSObjectToPropertyNode(args, propArgs);
90 }
91
93
94 return mgr->execute(cmdName, propArgs, globals->get_props());
95}
96
97FGQmlPropertyNode *FGQmlInstance::property(QString path, bool create) const
98{
99 SGPropertyNode_ptr node = fgGetNode(path.toStdString(), create);
100 if (!node)
101 return nullptr;
102
104 result->setNode(node);
105 return result;
106}
Q_INVOKABLE bool command(QString name, QJSValue args)
Q_INVOKABLE FGQmlPropertyNode * property(QString path, bool create=false) const
retrieve a property by its global path
FGQmlInstance(QObject *parent=nullptr)
void setNode(SGPropertyNode_ptr node)
const char * name
FGGlobals * globals
Definition globals.cxx:142
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27