FlightGear next
FGQmlPropertyNode.cxx
Go to the documentation of this file.
1// FGQmlPropertyNode.cxx - expose SGPropertyNode to QML
2//
3// Copyright (C) 2019 James Turner <james@flightgear.org>
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License as
7// published by the Free Software Foundation; either version 2 of the
8// License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful, but
11// WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19#include "config.h"
20
21#include "FGQmlPropertyNode.hxx"
22
23#include <QVector3D>
24#include <QVector4D>
25#include <QDebug>
26
27#include <simgear/props/props.hxx>
28#include <simgear/props/vectorPropTemplates.hxx>
29#include <simgear/math/SGMath.hxx>
30
31#include <Main/fg_props.hxx>
32
34
35FGQmlPropertyNode::FGQmlPropertyNode(QObject *parent) : QObject(parent)
36{
37
38}
39
40bool FGQmlPropertyNode::set(QVariant newValue)
41{
42 if (!_prop || !_prop->getAttribute(SGPropertyNode::WRITE))
43 return false;
44
45 // we still need to short circuit setting
46 if (newValue == value()) {
47 return true;
48 }
49
50 switch (_prop->getType()) {
51 case simgear::props::INT:
52 case simgear::props::LONG:
53 _prop->setIntValue(newValue.toInt());
54 case simgear::props::BOOL: _prop->setBoolValue(newValue.toBool());
55 case simgear::props::DOUBLE: _prop->setDoubleValue(newValue.toDouble());
56 case simgear::props::FLOAT: _prop->setFloatValue(newValue.toFloat());
57 case simgear::props::STRING: _prop->setStringValue(newValue.toString().toStdString());
58
59 case simgear::props::VEC3D: {
60 QVector3D v = newValue.value<QVector3D>();
61 _prop->setValue(SGVec3d(v.x(), v.y(), v.z()));
62 }
63
64 case simgear::props::VEC4D: {
65 QVector4D v = newValue.value<QVector4D>();
66 _prop->setValue(SGVec4d(v.x(), v.y(), v.z(), v.w()));
67 }
68
69 default:
70 qWarning() << Q_FUNC_INFO << "handle untyped property writes";
71 break;
72 }
73
74 return true;
75}
76
78{
79 return propertyValueAsVariant(_prop);
80}
81
83{
84 if (!_prop)
85 return QString();
86
87 return QString::fromStdString(_prop->getPath());
88}
89
91{
92 if (!_prop || !_prop->getParent())
93 return nullptr;
94
95 auto pp = new FGQmlPropertyNode;
96 pp->setNode(_prop->getParent());
97 return pp;
98}
99
100void FGQmlPropertyNode::setNode(SGPropertyNode_ptr node)
101{
102 if (node == _prop) {
103 return;
104 }
105
106 if (_prop) {
107 _prop->removeChangeListener(this);
108 }
109
110 _prop = node;
111 if (_prop) {
112 _prop->addChangeListener(this, false);
113 }
114
116 emit pathChanged(path());
118 emit childPropsChanged();
119}
120
121SGPropertyNode_ptr FGQmlPropertyNode::node() const
122{
123 return _prop;
124}
125
127{
128 if (!p)
129 return {};
130
131 switch (p->getType()) {
132 case simgear::props::INT:
133 case simgear::props::LONG:
134 return p->getIntValue();
135 case simgear::props::BOOL: return p->getBoolValue();
136 case simgear::props::DOUBLE: return p->getDoubleValue();
137 case simgear::props::FLOAT: return p->getFloatValue();
138 case simgear::props::STRING: return QString::fromStdString(p->getStringValue());
139
140 case simgear::props::VEC3D: {
141 const SGVec3d v3 = p->getValue<SGVec3d>();
142 return QVariant::fromValue(QVector3D(v3.x(), v3.y(), v3.z()));
143 }
144
145 case simgear::props::VEC4D: {
146 const SGVec4d v4 = p->getValue<SGVec4d>();
147 return QVariant::fromValue(QVector4D(v4.x(), v4.y(), v4.z(), v4.w()));
148 }
149 default:
150 break;
151 }
152
153 return {}; // null qvariant
154}
155
157{
158 if (node != _prop) {
159 return;
160 }
162}
163
164void FGQmlPropertyNode::childAdded(SGPropertyNode* pr, SGPropertyNode* child)
165{
166 if (pr == _prop) {
167 emit childPropsChanged();
168 }
169}
170
171void FGQmlPropertyNode::childRemoved(SGPropertyNode* pr, SGPropertyNode* child)
172{
173 if (pr == _prop) {
174 emit childPropsChanged();
175 }
176}
177
179{
180 SGPropertyNode_ptr node = fgGetNode(path.toStdString(), false /* don't create */);
181 setNode(node);
182}
183
184
186{
187 if (!_prop)
188 return 0;
189 return _prop->nChildren();
190}
191
193{
194 if (!_prop || (_prop->nChildren() <= index))
195 return nullptr;
196
197 auto pp = new FGQmlPropertyNode;
198 pp->setNode(_prop->getChild(index));
199 return pp;
200}
#define p(x)
Q_INVOKABLE bool set(QVariant newValue)
FGQmlPropertyNode * childAt(int index) const
void valueChangedNotify(QVariant value)
void parentPropChanged(FGQmlPropertyNode *parentProp)
SGPropertyNode_ptr node() const
static QVariant propertyValueAsVariant(SGPropertyNode *p)
void setNode(SGPropertyNode_ptr node)
void childPropsChanged()
void pathChanged(QString path)
FGQmlPropertyNode * parentProp
void setPath(QString path)
void childRemoved(SGPropertyNode *pr, SGPropertyNode *child) override
void childAdded(SGPropertyNode *pr, SGPropertyNode *child) override
FGQmlPropertyNode(QObject *parent=nullptr)
void valueChanged(SGPropertyNode *node) override
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27