added write support for VectorProperty
Dieser Commit ist enthalten in:
Ursprung
f26513ca55
Commit
4497d75e7a
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2021 Reinder Feenstra
|
||||
* Copyright (C) 2021,2024 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -60,6 +60,12 @@ class AbstractVectorProperty : public BaseProperty
|
||||
static_assert(is_set_v<T>);
|
||||
return static_cast<T>(getInt64(index));
|
||||
}
|
||||
|
||||
virtual void setBool(int /*index*/, bool /*value*/) { Q_ASSERT(false); }
|
||||
virtual void setInt(int /*index*/, int /*value*/) { Q_ASSERT(false); }
|
||||
virtual void setInt64(int /*index*/, qint64 /*value*/) { Q_ASSERT(false); }
|
||||
virtual void setDouble(int /*index*/, double /*value*/) { Q_ASSERT(false); }
|
||||
virtual void setString(int /*index*/, const QString& /*value*/) { Q_ASSERT(false); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
84
client/src/network/vectorproperty.cpp
Normale Datei
84
client/src/network/vectorproperty.cpp
Normale Datei
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* client/src/network/vectorproperty.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2024 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "vectorproperty.hpp"
|
||||
#include "connection.hpp"
|
||||
#include "object.hpp"
|
||||
|
||||
template<class T>
|
||||
static void setVectorPropertyValue(VectorProperty& property, int index, const T& value)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetVectorProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->handle());
|
||||
event->write(property.name().toLatin1());
|
||||
event->write<uint32_t>(index);
|
||||
|
||||
if constexpr(std::is_same_v<T, bool>)
|
||||
{
|
||||
event->write(ValueType::Boolean);
|
||||
event->write(value);
|
||||
}
|
||||
else if constexpr(std::is_integral_v<T>)
|
||||
{
|
||||
event->write(ValueType::Integer);
|
||||
event->write<int64_t>(value);
|
||||
}
|
||||
else if constexpr(std::is_floating_point_v<T>)
|
||||
{
|
||||
event->write(ValueType::Float);
|
||||
event->write<double>(value);
|
||||
}
|
||||
else if constexpr(std::is_same_v<T, QString>)
|
||||
{
|
||||
event->write(ValueType::String);
|
||||
event->write(value.toUtf8());
|
||||
}
|
||||
else
|
||||
static_assert(sizeof(T) != sizeof(T));
|
||||
|
||||
property.object().connection()->send(event);
|
||||
}
|
||||
|
||||
void VectorProperty::setBool(int index, bool value)
|
||||
{
|
||||
setVectorPropertyValue(*this, index, value);
|
||||
}
|
||||
|
||||
void VectorProperty::setInt(int index, int value)
|
||||
{
|
||||
setVectorPropertyValue(*this, index, value);
|
||||
}
|
||||
|
||||
void VectorProperty::setInt64(int index, qint64 value)
|
||||
{
|
||||
setVectorPropertyValue(*this, index, value);
|
||||
}
|
||||
|
||||
void VectorProperty::setDouble(int index, double value)
|
||||
{
|
||||
setVectorPropertyValue(*this, index, value);
|
||||
}
|
||||
|
||||
void VectorProperty::setString(int index, const QString& value)
|
||||
{
|
||||
setVectorPropertyValue(*this, index, value);
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2021 Reinder Feenstra
|
||||
* Copyright (C) 2021,2024 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -99,6 +99,12 @@ class VectorProperty : public AbstractVectorProperty
|
||||
Q_ASSERT(index >= 0 && index < size());
|
||||
return m_values[index];
|
||||
}
|
||||
|
||||
void setBool(int index, bool value) final;
|
||||
void setInt(int index, int value) final;
|
||||
void setInt64(int index, qint64 value) final;
|
||||
void setDouble(int index, double value) final;
|
||||
void setString(int index, const QString& value) final;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2021,2023 Reinder Feenstra
|
||||
* Copyright (C) 2021,2023-2024 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -30,18 +30,48 @@
|
||||
template<typename T>
|
||||
class VectorProperty : public AbstractVectorProperty
|
||||
{
|
||||
public:
|
||||
using OnChanged = std::function<void(uint32_t, std::conditional_t<valueTypeByRef<T>(), const T&, T> value)>;
|
||||
using OnSet = std::function<bool(uint32_t, T& value)>;
|
||||
|
||||
private:
|
||||
std::vector<T> m_values;
|
||||
OnChanged m_onChanged;
|
||||
OnSet m_onSet;
|
||||
|
||||
public:
|
||||
using const_iterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
VectorProperty(Object& object, std::string_view name, PropertyFlags flags)
|
||||
: AbstractVectorProperty(object, name, value_type<T>::value, flags)
|
||||
{
|
||||
}
|
||||
|
||||
VectorProperty(Object& object, std::string_view name, std::initializer_list<T> values, PropertyFlags flags) :
|
||||
AbstractVectorProperty(object, name, value_type<T>::value, flags),
|
||||
m_values{values}
|
||||
{
|
||||
}
|
||||
|
||||
VectorProperty(Object& object, std::string_view name, std::initializer_list<T> values, PropertyFlags flags, OnChanged onChanged)
|
||||
: VectorProperty(object, name, values, flags)
|
||||
{
|
||||
m_onChanged = std::move(onChanged);
|
||||
}
|
||||
|
||||
VectorProperty(Object& object, std::string_view name, std::initializer_list<T> values, PropertyFlags flags, OnChanged onChanged, OnSet onSet)
|
||||
: VectorProperty(object, name, values, flags)
|
||||
{
|
||||
m_onChanged = std::move(onChanged);
|
||||
m_onSet = std::move(onSet);
|
||||
}
|
||||
|
||||
VectorProperty(Object& object, std::string_view name, std::initializer_list<T> values, PropertyFlags flags, std::nullptr_t, OnSet onSet)
|
||||
: VectorProperty(object, name, values, flags)
|
||||
{
|
||||
m_onSet = std::move(onSet);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const { return m_values.begin(); }
|
||||
inline const_iterator end() const { return m_values.end(); }
|
||||
|
||||
@ -63,11 +93,81 @@ class VectorProperty : public AbstractVectorProperty
|
||||
return;
|
||||
else if(!isWriteable())
|
||||
throw not_writable_error();
|
||||
else
|
||||
|
||||
if constexpr(std::is_integral_v<T> || std::is_floating_point_v<T>)
|
||||
{
|
||||
if(auto it = m_attributes.find(AttributeName::Min); it != m_attributes.end())
|
||||
{
|
||||
const T min = static_cast<Attribute<T>&>(*it->second).value();
|
||||
|
||||
if(value < min)
|
||||
{
|
||||
if constexpr(std::is_floating_point_v<T>)
|
||||
{
|
||||
if(value > min - std::numeric_limits<T>::epsilon() * 100)
|
||||
value = min;
|
||||
else
|
||||
throw out_of_range_error();
|
||||
}
|
||||
else
|
||||
throw out_of_range_error();
|
||||
}
|
||||
}
|
||||
|
||||
if(auto it = m_attributes.find(AttributeName::Max); it != m_attributes.end())
|
||||
{
|
||||
const T max = static_cast<Attribute<T>&>(*it->second).value();
|
||||
|
||||
if(value > max)
|
||||
{
|
||||
if constexpr(std::is_floating_point_v<T>)
|
||||
{
|
||||
if(value < max + std::numeric_limits<T>::epsilon() * 100)
|
||||
value = max;
|
||||
else
|
||||
throw out_of_range_error();
|
||||
}
|
||||
else
|
||||
throw out_of_range_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(std::is_enum_v<T> && !is_set_v<T>)
|
||||
{
|
||||
if(auto it = m_attributes.find(AttributeName::Values); it != m_attributes.end())
|
||||
{
|
||||
if(auto* span = dynamic_cast<SpanAttribute<T>*>(it->second.get()))
|
||||
{
|
||||
const auto values = span->values();
|
||||
if(std::find(values.begin(), values.end(), value) == values.end())
|
||||
throw out_of_range_error();
|
||||
}
|
||||
else if(auto* vectorRef = dynamic_cast<VectorRefAttribute<T>*>(it->second.get()))
|
||||
{
|
||||
const auto* values = vectorRef->values();
|
||||
if(!values || std::find(values->begin(), values->end(), value) == values->end())
|
||||
throw out_of_range_error();
|
||||
}
|
||||
else if(auto* vector = dynamic_cast<VectorAttribute<T>*>(it->second.get()))
|
||||
{
|
||||
const auto& values = vector->values();
|
||||
if(std::find(values.begin(), values.end(), value) == values.end())
|
||||
throw out_of_range_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!m_onSet || m_onSet(index, value))
|
||||
{
|
||||
m_values[index] = value;
|
||||
if(m_onChanged)
|
||||
m_onChanged(index, m_values[index]);
|
||||
changed();
|
||||
return;
|
||||
}
|
||||
|
||||
throw invalid_value_error();
|
||||
}
|
||||
|
||||
void setValuesInternal(std::vector<T> values)
|
||||
@ -112,6 +212,12 @@ class VectorProperty : public AbstractVectorProperty
|
||||
changed();
|
||||
}
|
||||
|
||||
void clearInternal()
|
||||
{
|
||||
m_values.clear();
|
||||
changed();
|
||||
}
|
||||
|
||||
std::string_view enumName() const final
|
||||
{
|
||||
if constexpr(std::is_enum_v<T> && !is_set_v<T>)
|
||||
@ -130,6 +236,26 @@ class VectorProperty : public AbstractVectorProperty
|
||||
return "";
|
||||
}
|
||||
|
||||
inline const T& front() const
|
||||
{
|
||||
return m_values.front();
|
||||
}
|
||||
|
||||
inline T& front()
|
||||
{
|
||||
return m_values.front();
|
||||
}
|
||||
|
||||
inline const T& back() const
|
||||
{
|
||||
return m_values.back();
|
||||
}
|
||||
|
||||
inline T& back()
|
||||
{
|
||||
return m_values.back();
|
||||
}
|
||||
|
||||
inline size_t size() const final
|
||||
{
|
||||
return m_values.size();
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2023 Reinder Feenstra
|
||||
* Copyright (C) 2019-2024 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -195,6 +195,65 @@ bool Session::processMessage(const Message& message)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Message::Command::ObjectSetVectorProperty:
|
||||
{
|
||||
if(message.isRequest() || message.isEvent())
|
||||
{
|
||||
if(ObjectPtr object = m_handles.getItem(message.read<Handle>()))
|
||||
{
|
||||
if(AbstractVectorProperty* property = object->getVectorProperty(message.read<std::string>()); property && !property->isInternal())
|
||||
{
|
||||
try
|
||||
{
|
||||
const size_t index = message.read<uint32_t>();
|
||||
|
||||
switch(message.read<ValueType>())
|
||||
{
|
||||
case ValueType::Boolean:
|
||||
property->setBool(index, message.read<bool>());
|
||||
break;
|
||||
|
||||
case ValueType::Integer:
|
||||
property->setInt64(index, message.read<int64_t>());
|
||||
break;
|
||||
|
||||
case ValueType::Float:
|
||||
property->setDouble(index, message.read<double>());
|
||||
break;
|
||||
|
||||
case ValueType::String:
|
||||
property->setString(index, message.read<std::string>());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("invalid value type");
|
||||
}
|
||||
}
|
||||
catch(const std::exception& e) // set property failed
|
||||
{
|
||||
if(message.isRequest()) // send error response
|
||||
{
|
||||
m_connection->sendMessage(Message::newErrorResponse(message.command(), message.requestId(), LogMessage::C1018_EXCEPTION_X, e.what()));
|
||||
}
|
||||
else // send changed event with current value:
|
||||
objectPropertyChanged(*property);
|
||||
}
|
||||
|
||||
if(message.isRequest()) // send success response
|
||||
m_connection->sendMessage(Message::newResponse(message.command(), message.requestId()));
|
||||
}
|
||||
else if(message.isRequest()) // send error response
|
||||
{
|
||||
m_connection->sendMessage(Message::newErrorResponse(message.command(), message.requestId(), LogMessage::C1016_UNKNOWN_PROPERTY));
|
||||
}
|
||||
}
|
||||
else if(message.isRequest()) // send error response
|
||||
{
|
||||
m_connection->sendMessage(Message::newErrorResponse(message.command(), message.requestId(), LogMessage::C1015_UNKNOWN_OBJECT));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Message::Command::ObjectSetUnitPropertyUnit:
|
||||
{
|
||||
if(ObjectPtr object = m_handles.getItem(message.read<Handle>()))
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2023 Reinder Feenstra
|
||||
* Copyright (C) 2019-2024 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -88,6 +88,7 @@ class Message
|
||||
|
||||
ObjectGetObjectPropertyObject = 44,
|
||||
ObjectGetObjectVectorPropertyObject = 45,
|
||||
ObjectSetVectorProperty = 46,
|
||||
|
||||
Discover = 255,
|
||||
};
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren