blob: b8158fe3f8e09b25cf2e0b869e08553f0d056ffe [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_METADATA_PROPERTY_METADATA_H_
#define UI_BASE_METADATA_PROPERTY_METADATA_H_
#include <string>
#include <type_traits>
#include <utility>
#include "base/component_export.h"
#include "base/macros.h"
#include "ui/base/class_property.h"
#include "ui/base/metadata/base_type_conversion.h"
#include "ui/base/metadata/metadata_cache.h"
#include "ui/base/metadata/metadata_types.h"
namespace ui {
namespace metadata {
namespace internal {
template <typename TSource, typename TTarget, typename = void>
struct DeRefHelper {
static TTarget Get(TSource value) { return value; }
};
template <typename TSource, typename TTarget>
struct DeRefHelper<
TSource,
TTarget,
typename std::enable_if<!std::is_same<TSource, TTarget>::value>::type> {
static TTarget Get(TSource value) { return *value; }
};
template <typename TKey, typename TValue>
struct ClassPropertyMetaDataTypeHelper;
template <typename TKValue_, typename TValue_>
struct ClassPropertyMetaDataTypeHelper<const ui::ClassProperty<TKValue_>* const,
TValue_> {
using TKValue = TKValue_;
using TValue = TValue_;
// Returns |value| when |TKValue| == |TValue|. Otherwise, TKValue must be the
// pointer type to TValue, returns |*value| instead.
// This is useful for owned propertyies like ui::ClassProperty<gfx::Insets*>
// where we want to inspect the actual value, rather than the pointer.
static TValue DeRef(TKValue value) {
return DeRefHelper<TKValue, TValue>::Get(value);
}
};
// Works around static casting issues related to the void*. See the comment on
// the METADATA_ACCESSORS_INTERNAL_BASE macro for more information about why
// this is necessary. NOTE: The reinterpret_cast<> here is merely to bring
// ReinterpretToBaseClass() into scope and make it callable. The body of that
// function does not access |this|, so this call is safe.
template <typename TClass>
TClass* AsClass(void* obj) {
return static_cast<TClass*>(
reinterpret_cast<TClass*>(obj)->ReinterpretToBaseClass(obj));
}
} // namespace internal
// Represents meta data for a specific read-only property member of class
// |TClass|, with underlying type |TValue|, as the type of the actual member.
// Using a separate |TRet| type for the getter function's return type to allow
// it to return a type with qualifier and by reference.
template <typename TClass,
typename TValue,
typename TRet,
TRet (TClass::*Get)() const,
typename TConverter = ui::metadata::TypeConverter<TValue>>
class ObjectPropertyReadOnlyMetaData : public ui::metadata::MemberMetaDataBase {
public:
using MemberMetaDataBase::MemberMetaDataBase;
ObjectPropertyReadOnlyMetaData(const ObjectPropertyReadOnlyMetaData&) =
delete;
ObjectPropertyReadOnlyMetaData& operator=(
const ObjectPropertyReadOnlyMetaData&) = delete;
~ObjectPropertyReadOnlyMetaData() override = default;
std::u16string GetValueAsString(void* obj) const override {
if (!kTypeIsSerializable && !kTypeIsReadOnly)
return std::u16string();
return TConverter::ToString((internal::AsClass<TClass>(obj)->*Get)());
}
ui::metadata::PropertyFlags GetPropertyFlags() const override {
return kTypeIsSerializable ? (ui::metadata::PropertyFlags::kReadOnly |
ui::metadata::PropertyFlags::kSerializable)
: ui::metadata::PropertyFlags::kReadOnly;
}
const char* GetMemberNamePrefix() const override {
return TConverter::PropertyNamePrefix();
}
private:
static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
// Represents meta data for a specific property member of class |TClass|, with
// underlying type |TValue|, as the type of the actual member.
// Allows for interaction with the property as if it were the underlying data
// type (|TValue|), but still uses the Property's functionality under the hood
// (so it will trigger things like property changed notifications).
template <typename TClass,
typename TValue,
typename TSig,
TSig Set,
typename TRet,
TRet (TClass::*Get)() const,
typename TConverter = ui::metadata::TypeConverter<TValue>>
class ObjectPropertyMetaData
: public ObjectPropertyReadOnlyMetaData<TClass,
TValue,
TRet,
Get,
TConverter> {
public:
using ObjectPropertyReadOnlyMetaData<TClass, TValue, TRet, Get, TConverter>::
ObjectPropertyReadOnlyMetaData;
ObjectPropertyMetaData(const ObjectPropertyMetaData&) = delete;
ObjectPropertyMetaData& operator=(const ObjectPropertyMetaData&) = delete;
~ObjectPropertyMetaData() override = default;
void SetValueAsString(void* obj, const std::u16string& new_value) override {
if (!kTypeIsSerializable || kTypeIsReadOnly)
return;
if (absl::optional<TValue> result = TConverter::FromString(new_value)) {
(internal::AsClass<TClass>(obj)->*Set)(std::move(result.value()));
}
}
ui::metadata::MemberMetaDataBase::ValueStrings GetValidValues()
const override {
if (!kTypeIsSerializable)
return {};
return TConverter::GetValidStrings();
}
ui::metadata::PropertyFlags GetPropertyFlags() const override {
ui::metadata::PropertyFlags flags = ui::metadata::PropertyFlags::kEmpty;
if (kTypeIsSerializable)
flags = flags | ui::metadata::PropertyFlags::kSerializable;
if (kTypeIsReadOnly)
flags = flags | ui::metadata::PropertyFlags::kReadOnly;
return flags;
}
private:
static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
// Represents metadata for a ui::ClassProperty attached on a class instance.
// Converts property value to |TValue| when possible. This allows inspecting
// the actual value when the property is a pointer of type |TValue*|.
template <typename TClass,
typename TKey,
typename TValue,
typename TConverter = ui::metadata::TypeConverter<TValue>>
class ClassPropertyMetaData : public ui::metadata::MemberMetaDataBase {
public:
using TypeHelper = internal::ClassPropertyMetaDataTypeHelper<TKey, TValue>;
ClassPropertyMetaData(TKey key, const std::string& property_type)
: MemberMetaDataBase(key->name, property_type), key_(key) {}
ClassPropertyMetaData(const ClassPropertyMetaData&) = delete;
ClassPropertyMetaData& operator=(const ClassPropertyMetaData&) = delete;
~ClassPropertyMetaData() override = default;
// Returns the property value as a string.
// If the property value is an pointer of type |TKValue*| and
// |TKValue| == |TValue|, dereferences the pointer.
std::u16string GetValueAsString(void* obj) const override {
typename TypeHelper::TKValue value =
internal::AsClass<TClass>(obj)->GetProperty(key_);
if (std::is_pointer<typename TypeHelper::TKValue>::value && !value) {
return u"(not assigned)";
} else {
// GetProperty() returns a pointer when this is an owned property.
// If |TValue| is not pointer, DeRef() returns |*value|, otherwise
// it returns |value| as it is.
return TConverter::ToString(TypeHelper::DeRef(value));
}
}
void SetValueAsString(void* obj, const std::u16string& new_value) override {
absl::optional<TValue> value = TConverter::FromString(new_value);
if (value)
internal::AsClass<TClass>(obj)->SetProperty(key_, *value);
}
ui::metadata::PropertyFlags GetPropertyFlags() const override {
ui::metadata::PropertyFlags flags = ui::metadata::PropertyFlags::kEmpty;
if (kTypeIsSerializable)
flags = flags | ui::metadata::PropertyFlags::kSerializable;
if (kTypeIsReadOnly)
flags = flags | ui::metadata::PropertyFlags::kReadOnly;
return flags;
}
private:
TKey key_;
static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
} // namespace metadata
} // namespace ui
#endif // UI_BASE_METADATA_PROPERTY_METADATA_H_