Stellarium  23.4
Public Slots | Signals | Protected Slots | Protected Member Functions | Protected Attributes | Friends
StelProperty Class Reference

Wrapper around a Q_PROPERTY (see the Qt property system for more information) of a specific object, which provides access to the property through a unique ID. More...

#include <StelPropertyMgr.hpp>

Public Slots

QString getId () const
 Returns the unique ID which is used to identify this property.
 
QVariant getValue () const
 Returns the current value of this property as a QVariant.
 
bool setValue (const QVariant &value) const
 Sets the value of the property. More...
 
bool isReadOnly () const
 If false, setValue can be used.
 
bool isSynchronizable () const
 True when this property can be synchronized with external sources. More...
 
bool canNotify () const
 If true, the Q_PROPERTY has a NOTIFY signal and the changed() signal can be used.
 
QMetaType::Type getType () const
 Returns the data type of the StelProperty.
 
QMetaProperty getMetaProp () const
 Returns the actual Q_PROPERTY wrapped by this instance.
 
QObject * getTarget () const
 Returns the object to which this property belongs.
 

Signals

void changed (const QVariant &newValue)
 Emitted when the value of the property changed.
 

Protected Slots

void propertyChanged ()
 Reacts to NOTIFY signals from the object (ignoring the optional parameter), and emits the changed signal.
 

Protected Member Functions

 StelProperty (const QString &id, QObject *target, const QMetaProperty &prop)
 

Protected Attributes

QString id
 
QObject * target
 
QMetaProperty prop
 

Friends

class StelPropertyMgr
 

Detailed Description

Wrapper around a Q_PROPERTY (see the Qt property system for more information) of a specific object, which provides access to the property through a unique ID.

A StelProperty basically is a tuple of <QObject* target, QMetaProperty prop> identified by a unique string ID that allows to access the property prop of the target, without the requirement of needing information about the classes, data types and method signatures involved. The StelPropertyMgr acts as a global registry for this information. In some ways, this is similar to how StelAction worked with boolean properties - but with arbitrary data.

The use of this class allows easy access to non-boolean Stellarium settings for GUI data-binding (see StelDialog for binding functions) and enables external interfaces, such scripting or the Remote Control Plug-in plugin to access and change the property dynamically. The main differences to StelAction are:

To register a new StelProperty, use the StelPropertyMgr, which can be retrieved using StelApp::getStelPropertyManager(). By default, if you are using a StelModule (and it is registered with the StelModuleMgr), all the properties of your object are automatically exposed through StelProperty instances, so in most cases you don't need to do anything more than define your Q_PROPERTY correctly.

To register all properties of a QObject automatically, you can use StelPropertyMgr::registerObject, which generates a StelProperty with an ID in the format <objectName>.<propertyName> for all Q_PROPERTY definitions on the class. Single properties can be registered with StelPropertyMgr::registerProperty.

The linked Q_PROPERTY must be valid, that is it has to have at least the READ function and/or a MEMBER definition. Furthermore, it is highly recommended to have the NOTIFY signal correctly implemented, so that interested objects can be notified as soon as the property changes. If a property has the WRITE function (or is defined as MEMBER), its value can be set through this class. For optimal results, when changing the property (e.g. through the WRITE slot), it should be checked if the value really has changed before emitting the NOTIFY signal to prevent unnecessary processing. StelProperty supports all data types that work with Q_PROPERTY and QVariant. When using custom types, Q_DECLARE_METATYPE and/or qRegisterMetaType() may be needed. If custom data types are required to be accessed from outside the program (for example through the [Remote Control Plug-in documentation](RemoteControl plugin) ), some further work may be required to serialize/deserialize them, but all standard data types (bool, int, double, QString ...) work seamlessly out of the box.

Each StelProperty is identified by an unique QString ID. Properties registered by StelPropertyMgr::registerObject, which includes all StelModule instances registered with the StelModuleMgr, are identified with an ID in the format <objectName>.<propertyName>.

A full example how to define a Q_PROPERTY, using a StelModule:

class MyCustomModule : public StelModule
{
Q_OBJECT
Q_PROPERTY(int awesomeProperty READ getAwesomeProperty WRITE setAwesomeProperty NOTIFY awesomePropertyChanged)
public:
MyCustomModule()
{
//this is not even required for a StelModule
//because the base class constructor sets the object name to the class name
//using QMetaObject runtime information
setObjectName("MyCustomModule");
}
...
void init() Q_DECL_OVERRIDE
{
...
// to manually register the property as a StelProperty, this could be used,
// but it is not even required (nor recommended!) because we are in a StelModule!
//registerProperty("my_arbitrary_ID_for_MyCustomModule_awesomeProperty", "awesomeProperty");
...
}
void printProperty()
{
qDebug()<<prop;
}
public slots:
//Returns the current awesomeProperty value
int getAwesomeProperty() const { return prop; }
//Sets the awesomeProperty
//Don't forget to emit the NOTIFY signal if the value actually changed!
void setAwesomeProperty(int val) { if(val!=prop) { prop = val; emit awesomePropertyChanged(val); } }
signals:
void awesomePropertyChanged(int newVal);
private:
int prop;
};

After registration, the property can then be used from arbitrary other code, like so:

StelProperty* prop = StelApp::getInstance().getStelPropertyManager()->getProperty("MyCustomModule.awesomeProperty");
prop->setValue(123); //this performs data type conversion if necessary, using QVariant
//alternatively, use this to skip having to get the StelProperty instance:
//StelApp::getInstance().getStelPropertyManager()->setStelPropertyValue("MyCustomModule.awesomeProperty", 123);
// or even, much shorter, assuming awesomeProperty is an int,
// GETSTELPROPERTYVALUE("MyCustomModule.awesomeProperty").toInt();
//to see the effect
MyCustomModule *module = GETSTELMODULE(MyCustomModule);
module->printProperty(); //prints 123

The changed() signal can be used to detect whenever the property changes. To connect the changed() signal to slots which expect a specific type instead of a QVariant, a StelPropertyProxy implementation can be used. This file defines StelPropertyIntProxy, StelPropertyBoolProxy and StelPropertyDoubleProxy, which use QVariant-based type conversion if necessary.

Of course, the whole StelProperty system does not prevent you from directly using/connecting the properties' signals and slots, 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. Other connections using a StelProperty will work seamlessly.

StelDialog supports helper methods for two-way binding using common Qt Widgets and datatypes.

Note
Good candidates for a StelProperty are properties that do not change too often. This includes most settings configurable through the GUI. Bad examples are properties which potentially change very often (e.g. each frame), such as the current view vector, field of view etc. They may cause considerable overhead if used, and therefore should be avoided.
See also
StelPropertyMgr, StelDialog, StelAction

Member Function Documentation

◆ isSynchronizable

bool StelProperty::isSynchronizable ( ) const
slot

True when this property can be synchronized with external sources.

This is the case when it is writable, and it is marked as STORED true (default).

◆ setValue

bool StelProperty::setValue ( const QVariant &  value) const
slot

Sets the value of the property.

This can only be used if isReadOnly is false, meaning a WRITE function is defined on the Q_PROPERTY. Data type conversion is performed, if necessary, using the internal logic of QVariant. This basically means that QVariant::canConvert() from the given value to the actual data type of the Q_PROPERTY must be true for the operation to succeed.

Returns
true if the new value was successfully set