• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 4853788370

pending completion
4853788370

push

github

Alexander V. Wolf
Special patch for John Simple

3 of 3 new or added lines in 3 files covered. (100.0%)

14729 of 125046 relevant lines covered (11.78%)

20166.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/core/StelPropertyMgr.hpp
1
/*
2
 * Copyright (C) 2015-2016 Florian Schaukowitsch
3
 *
4
 * This program is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU General Public License
6
 * as published by the Free Software Foundation; either version 2
7
 * of the License, or (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
17
 */
18

19
#ifndef STELPROPERTYMGR_HPP
20
#define STELPROPERTYMGR_HPP
21

22
#include <QObject>
23
#include <QSet>
24
#include <QMetaProperty>
25

26
class StelProperty;
27

28
//! Abstract base class for a StelProperty proxy implementation, which allow reacting to the
29
//! StelProperty::changed event using a specific type instead of reacting to the QVariant version.
30
//! This is required for some connections such as in the UI.
31
//! The intended use is to subclass this class and implement the onPropertyChanged() slot,
32
//! re-emitting the "changed" event with a type-converted value.
33
class StelPropertyProxy : public QObject
34
{
35
        Q_OBJECT
36
public:
37
        StelPropertyProxy(StelProperty* prop,QObject* parent);
38

39
protected slots:
40
        //! This is connected by the constructor to the StelProperty::changed event
41
        //! of the connected property
42
        virtual void onPropertyChanged(const QVariant& value) = 0;
43

44
protected:
45
        //! The connected property, set by the constructor
46
        StelProperty* prop;
47
};
48

49
//! A StelPropertyProxy for int-based properties
50
class StelPropertyIntProxy : public StelPropertyProxy
51
{
52
        Q_OBJECT
53
public:
54
        StelPropertyIntProxy(StelProperty* prop,QObject* parent);
55
protected slots:
56
        void onPropertyChanged(const QVariant &value) Q_DECL_OVERRIDE;
57
signals:
58
        //! Emitted when the property value changes
59
        void propertyChanged(int value);
60
};
61

62
//! A StelPropertyProxy for bool-based properties
63
class StelPropertyBoolProxy : public StelPropertyProxy
64
{
65
        Q_OBJECT
66
public:
67
        StelPropertyBoolProxy(StelProperty* prop,QObject* parent);
68
protected slots:
69
        void onPropertyChanged(const QVariant &value) Q_DECL_OVERRIDE;
70
signals:
71
        //! Emitted when the property value changes
72
        void propertyChanged(bool value);
73
};
74

75
//! A StelPropertyProxy for double-based properties
76
class StelPropertyDoubleProxy : public StelPropertyProxy
77
{
78
        Q_OBJECT
79
public:
80
        StelPropertyDoubleProxy(StelProperty* prop,QObject* parent);
81
protected slots:
82
        void onPropertyChanged(const QVariant &value) Q_DECL_OVERRIDE;
83
signals:
84
        //! Emitted when the property value changes
85
        void propertyChanged(double value);
86
};
87

88
//! A StelPropertyProxy for QString-based properties
89
class StelPropertyStringProxy : public StelPropertyProxy
90
{
91
        Q_OBJECT
92
public:
93
        StelPropertyStringProxy(StelProperty* prop,QObject* parent);
94
protected slots:
95
        void onPropertyChanged(const QVariant &value) Q_DECL_OVERRIDE;
96
signals:
97
        //! Emitted when the property value changes
98
        void propertyChanged(QString value);
99
};
100

101
//! Wrapper around a Q_PROPERTY (see the [Qt property system](https://doc.qt.io/qt-5/properties.html) for more information) of a specific object, which provides access to the property through a unique ID.
102
//! A StelProperty basically is a tuple of `<QObject* target, QMetaProperty prop>` identified by a unique string ID
103
//! that allows to access the property \p prop of the \p target, without the requirement of needing information about the
104
//! classes, data types and method signatures involved. The StelPropertyMgr acts as a global registry for this information.
105
//! In some ways, this is similar to how StelAction worked with boolean properties - but with arbitrary data.
106
//!
107
//! The use of this class allows easy access to non-boolean Stellarium settings
108
//! for GUI data-binding (see StelDialog for binding functions) and enables external interfaces, such scripting or
109
//! the @ref remoteControl plugin to access and change the property dynamically. The main differences to StelAction are:
110
//! - The most important difference is that StelAction is primarily intended for user actions through keyboard shortcuts and/or GUI buttons.
111
//!   StelProperty is not intended to be directly used/configurable by users, but rather as a development tool,
112
//!   to easily access and modify the configurable options of all StelModule objects.
113
//! - StelProperty always requires a Q_PROPERTY while StelAction can also work directly with
114
//!   argumentless or boolean slots (i.e. func(), func(bool))
115
//! - StelAction actually registers and uses a StelProperty internally, if possible. This is the case when
116
//!   connected to a bool Q_PROPERTY instead of a slot. The created StelProperty has the same ID as the StelAction.
117
//! - StelProperty uses the NOTIFY handler to find out when the value changes, even if the change originated outside
118
//!   in non-StelProperty code by calling the WRITE slot directly.
119
//!   StelAction (if not using a StelProperty, as explained in the previous point) has to track boolean states on its own,
120
//!   so there may be a mismatch between the state as StelAction sees it and the real state in some cases
121
//!
122
//! To register a new StelProperty, use the StelPropertyMgr, which can be retrieved using StelApp::getStelPropertyManager().
123
//! By default, if you are using a StelModule (and it is registered with the StelModuleMgr), *all* the properties of your object
124
//! are automatically exposed through StelProperty instances, so in most cases you don't need to do *anything* more than define
125
//! your Q_PROPERTY correctly.
126
//!
127
//! To register all properties of a QObject automatically, you can use StelPropertyMgr::registerObject, which
128
//! generates a StelProperty with an ID in the format `<objectName>.<propertyName>` for all Q_PROPERTY definitions on the class.
129
//! Single properties can be registered with StelPropertyMgr::registerProperty.
130
//!
131
//! The linked Q_PROPERTY must be valid, that is it has to have at least the READ function and/or a MEMBER definition.
132
//! Furthermore, it is highly recommended to have the NOTIFY signal correctly implemented, so that interested objects
133
//! can be notified as soon as the property changes.
134
//! If a property has the WRITE function (or is defined as MEMBER), its value can be set through this class.
135
//! For optimal results, when changing the property (e.g. through the WRITE slot), it should be checked if the value
136
//! really has changed before emitting the NOTIFY signal to prevent unnecessary processing.
137
//! StelProperty supports all data types that work with Q_PROPERTY and QVariant. When using custom types,
138
//! Q_DECLARE_METATYPE and/or qRegisterMetaType() may be needed. If custom data types are required to be accessed from
139
//! outside the program (for example through the [\ref remoteControlDoc](RemoteControl plugin) ), some further work may be required
140
//! to serialize/deserialize them, but all standard data types (\c bool, \c int, \c double, \c QString ...) work seamlessly out of
141
//! the box.
142
//!
143
//! Each StelProperty is identified by an unique QString ID.
144
//! Properties registered by StelPropertyMgr::registerObject, which includes all StelModule instances registered with the StelModuleMgr,
145
//! are identified with an ID in the format `<objectName>.<propertyName>`.
146
//!
147
//! A full example how to define a Q_PROPERTY, using a StelModule:
148
//! \code
149
//! class MyCustomModule : public StelModule
150
//! {
151
//!                Q_OBJECT
152
//!                Q_PROPERTY(int awesomeProperty READ getAwesomeProperty WRITE setAwesomeProperty NOTIFY awesomePropertyChanged)
153
//!
154
//!        public:
155
//!                MyCustomModule()
156
//!                {
157
//!                        //this is not even required for a StelModule
158
//!                        //because the base class constructor sets the object name to the class name
159
//!                        //using QMetaObject runtime information
160
//!                        setObjectName("MyCustomModule");
161
//!                }
162
//!                ...
163
//!                void init() Q_DECL_OVERRIDE
164
//!                {
165
//!                        ...
166
//!                        // to manually register the property as a StelProperty, this could be used,
167
//!                        // but it is not even required (nor recommended!) because we are in a StelModule!
168
//!                        //registerProperty("my_arbitrary_ID_for_MyCustomModule_awesomeProperty", "awesomeProperty");
169
//!                        ...
170
//!                }
171
//!
172
//!                void printProperty()
173
//!                {
174
//!                        qDebug()<<prop;
175
//!                }
176
//!        public slots:
177
//!                //Returns the current awesomeProperty value
178
//!                int getAwesomeProperty() const { return prop; }
179
//!
180
//!                //Sets the awesomeProperty
181
//!                //Don't forget to emit the NOTIFY signal if the value actually changed!
182
//!                void setAwesomeProperty(int val) { if(val!=prop) { prop = val; emit awesomePropertyChanged(val); } }
183
//!        signals:
184
//!                void awesomePropertyChanged(int newVal);
185
//!        private:
186
//!                int prop;
187
//! };
188
//! \endcode
189
//!
190
//! After registration, the property can then be used from arbitrary other code, like so:
191
//! \code
192
//!        StelProperty* prop = StelApp::getInstance().getStelPropertyManager()->getProperty("MyCustomModule.awesomeProperty");
193
//!        prop->setValue(123);  //this performs data type conversion if necessary, using QVariant
194
//!
195
//!        //alternatively, use this to skip having to get the StelProperty instance:
196
//!        //StelApp::getInstance().getStelPropertyManager()->setStelPropertyValue("MyCustomModule.awesomeProperty", 123);
197
//!
198
//!        //to see the effect
199
//!        MyCustomModule *module = GETSTELMODULE(MyCustomModule);
200
//!        module->printProperty(); //prints 123
201
//! \endcode
202
//!
203
//! The changed() signal can be used to detect whenever the property changes. To connect the changed() signal
204
//! to slots which expect a specific type instead of a QVariant, a StelPropertyProxy implementation can be used.
205
//! This file defines StelPropertyIntProxy, StelPropertyBoolProxy and StelPropertyDoubleProxy, which use QVariant-based
206
//! type conversion if necessary.
207
//!
208
//! Of course, the whole StelProperty system does not prevent you from directly using/connecting the properties' signals and slots,
209
//! which is still recommended if you don't need two-way data binding (for example only reading the current value) because of a lower overhead.
210
//! Other connections using a StelProperty will work seamlessly.
211
//!
212
//! StelDialog supports helper methods for two-way binding using common %Qt Widgets and datatypes.
213
//!
214
//! @note Good candidates for a StelProperty are properties that do not change too often. This includes most settings
215
//! configurable through the GUI. Bad examples are properties which potentially change very often (e.g. each frame), such as the
216
//! current view vector, field of view etc. They may cause considerable overhead if used, and therefore should be avoided.
217
//! @sa StelPropertyMgr, StelDialog, StelAction
218
class StelProperty : public QObject
219
{
220
        friend class StelPropertyMgr;
221
        Q_OBJECT
222

223
public slots:
224
        //! Returns the unique ID which is used to identify this property
225
        QString getId() const { return id; }
×
226

227
        //! Returns the current value of this property as a QVariant
228
        QVariant getValue() const;
229

230
        //! Sets the value of the property. This can only be used if
231
        //! isReadOnly is false, meaning a WRITE function is defined on the Q_PROPERTY.
232
        //! Data type conversion is performed, if necessary, using the internal logic of
233
        //! QVariant. This basically means that QVariant::canConvert() from the given value
234
        //! to the actual data type of the Q_PROPERTY must be true for the operation to succeed.
235
        //! @return true if the new value was successfully set
236
        bool setValue(const QVariant& value) const;
237

238
        //! If false, setValue can be used.
239
        bool isReadOnly() const;
240

241
        //! True when this property can be synchronized with external sources.
242
        //! This is the case when it is writable, and it is marked as \c STORED true (default).
243
        bool isSynchronizable() const;
244

245
        //! If true, the Q_PROPERTY has a NOTIFY signal and the changed() signal can be used
246
        bool canNotify() const;
247

248
        //! Returns the data type of the StelProperty
249
        QMetaType::Type getType() const;
250

251
        //! Returns the actual Q_PROPERTY wrapped by this instance
252
        QMetaProperty getMetaProp() const { return prop; }
×
253

254
        //! Returns the object to which this property belongs
255
        QObject* getTarget() const { return target; }
×
256
signals:
257
        //! Emitted when the value of the property changed
258
        void changed(const QVariant& newValue);
259
protected slots:
260
        //! Reacts to NOTIFY signals from the object (ignoring the optional parameter), and emits the changed signal
261
        void propertyChanged();
262
protected:
263
        StelProperty(const QString& id,QObject* target, const QMetaProperty& prop);
264

265
        QString id;
266
        QObject* target;
267
        QMetaProperty prop;
268
};
269

270
//! Manages the registration of specific object properties with the StelProperty system.
271
//! A shortcut exists through StelModule::registerProperty.
272
//! For more information on how to use this system, see the StelProperty class.
273
class StelPropertyMgr : public QObject
274
{
275
        Q_OBJECT
276
public:
277
        typedef QMap<QString,StelProperty*> StelPropertyMap;
278

279
        //! Use StelApp::getStelPropertyManager to get the global instance
280
        StelPropertyMgr();
281
        ~StelPropertyMgr();
282

283
        //! Manually register a new StelProperty.
284
        //! @param id The identifier of the property. Must be unique, app will exit otherwise. It should follow
285
        //! the naming conventions as described in StelProperty.
286
        //! @param target The QObject which contains the property.
287
        //! @param propertyName The name of the Q_PROPERTY on the \c target which should be linked
288
        //! @returns a new StelProperty linking to the property with name \c propertyName on the \c target object
289
        StelProperty* registerProperty(const QString& id, QObject* target, const char* propertyName);
290

291
        //! Registers all Q_PROPERTY definitions on this object as StelProperty.
292
        //! The object must have an unique QObject::objectName, and this name should never
293
        //! change after registering. For all properties on this object, a
294
        //! StelProperty with an ID in the format `<objectName>.<propertyName>` is generated.
295
        void registerObject(QObject *obj);
296

297
        //! Returns the keys of all registered StelProperties
298
        QStringList getPropertyList() const;
299
        //! Returns all currently registered StelProperty instances
300
        QList<StelProperty*> getAllProperties() const;
301
        //! Returns a map from property IDs to StelProperty objects
302
        const StelPropertyMap& getPropertyMap() const { return propMap; }
×
303

304
        //! Returns the StelProperty with the specified ID, or Q_NULLPTR if not registered.
305
        //! If not registered, a warning is written to logfile unless noWarning is true.
306
        //! This may be useful to suppress warnings about plugin module properties
307
        //! when these are not loaded, but should else be left true.
308
        StelProperty* getProperty(const QString& id, const bool noWarning=false) const;
309

310
        //! Retrieves the current value of the given StelProperty,
311
        //! without requiring the retrieval of its object first.
312
        //! @returns the current value of the StelProperty with the ID \p id,
313
        //! or an invalid QVariant when no property with the given ID is found.
314
        //! If not found, a warning is written to logfile unless noWarning is true.
315
        //! This may be useful to suppress warnings about plugin module properties
316
        //! when these are not loaded, but should else be left true.
317
        QVariant getStelPropertyValue(const QString& id, const bool noWarning=false) const;
318
        //! Sets the value of the given StelProperty,
319
        //! without requiring the retrieval of its object first.
320
        //! @returns \c true when the value of the StelProperty with the ID \p id
321
        //! has been successfully changed, and \c false if the value change failed
322
        //! or when no property with the given ID is found.
323
        bool setStelPropertyValue(const QString& id, const QVariant &value) const;
324
        //! Returns the QMetaProperty information for the given \p id.
325
        QMetaProperty getMetaProperty(const QString& id) const;
326
signals:
327
        //! Emitted when any registered StelProperty has been changed
328
        //! @param prop The property that was changed
329
        //! @param value The new value of the property
330
        void stelPropertyChanged(StelProperty* prop, const QVariant& value);
331
private slots:
332
        void onStelPropChanged(const QVariant& val);
333
private:
334
        StelProperty* registerProperty(const QString &id, QObject *target, const QMetaProperty& prop);
335

336
        QMap<QString,QObject*> registeredObjects;
337
        StelPropertyMap propMap;
338
};
339

340
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc