blob: f4c7005144b0ac11323b9fbbbfd1e2cdd4a30676 [file] [log] [blame]
// Copyright 2021 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.
#include "components/ui_devtools/views/ui_element_with_metadata.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/views/element_utility.h"
#include "ui/base/metadata/metadata_types.h"
namespace ui_devtools {
namespace {
// Remove any custom editor "prefixes" from the property name. The prefixes must
// not be valid identifier characters.
void StripPrefix(std::string& property_name) {
auto cur = property_name.cbegin();
for (; cur < property_name.cend(); ++cur) {
if ((*cur >= 'A' && *cur <= 'Z') || (*cur >= 'a' && *cur <= 'z') ||
*cur == '_') {
break;
}
}
property_name.erase(property_name.cbegin(), cur);
}
} // namespace
UIElementWithMetaData::UIElementWithMetaData(const UIElementType type,
UIElementDelegate* delegate,
UIElement* parent)
: UIElement(type, delegate, parent) {}
UIElementWithMetaData::~UIElementWithMetaData() = default;
std::vector<UIElement::ClassProperties>
UIElementWithMetaData::GetCustomPropertiesForMatchedStyle() const {
std::vector<UIElement::ClassProperties> ret;
std::vector<UIElement::UIProperty> class_properties;
ui::Layer* layer = GetLayer();
if (layer) {
AppendLayerPropertiesMatchedStyle(layer, &class_properties);
ret.emplace_back("Layer", class_properties);
class_properties.clear();
}
ui::metadata::ClassMetaData* metadata = GetClassMetaData();
void* instance = GetClassInstance();
for (auto member = metadata->begin(); member != metadata->end(); member++) {
auto flags = (*member)->GetPropertyFlags();
if (!!(flags & ui::metadata::PropertyFlags::kSerializable) ||
!!(flags & ui::metadata::PropertyFlags::kReadOnly)) {
class_properties.emplace_back(
(*member)->GetMemberNamePrefix() + (*member)->member_name(),
base::UTF16ToUTF8((*member)->GetValueAsString(instance)));
}
if (member.IsLastMember()) {
ret.emplace_back(member.GetCurrentCollectionName(), class_properties);
class_properties.clear();
}
}
return ret;
}
void UIElementWithMetaData::GetVisible(bool* visible) const {
// Visibility information should be directly retrieved from element's
// metadata, no need for this function any more.
NOTREACHED();
}
void UIElementWithMetaData::SetVisible(bool visible) {
// Intentional No-op.
}
bool UIElementWithMetaData::SetPropertiesFromString(const std::string& text) {
bool property_set = false;
std::vector<std::string> tokens = base::SplitString(
text, ":;", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (tokens.size() == 0UL)
return false;
ui::metadata::ClassMetaData* metadata = GetClassMetaData();
void* instance = GetClassInstance();
for (size_t i = 0; i < tokens.size() - 1; i += 2) {
std::string property_name = tokens.at(i);
std::string property_value = base::ToLowerASCII(tokens.at(i + 1));
// Remove any type editor "prefixes" from the property name.
StripPrefix(property_name);
ui::metadata::MemberMetaDataBase* member =
metadata->FindMemberData(property_name);
if (!member) {
DLOG(ERROR) << "UI DevTools: Can not find property " << property_name
<< " in MetaData.";
continue;
}
// Since DevTools frontend doesn't check the value, we do a sanity check
// based on the allowed values specified in the metadata.
auto valid_values = member->GetValidValues();
if (!valid_values.empty() &&
std::find(valid_values.begin(), valid_values.end(),
base::UTF8ToUTF16(property_value)) == valid_values.end()) {
// Ignore the value.
continue;
}
auto property_flags = member->GetPropertyFlags();
if (!!(property_flags & ui::metadata::PropertyFlags::kReadOnly))
continue;
DCHECK(!!(property_flags & ui::metadata::PropertyFlags::kSerializable));
member->SetValueAsString(instance, base::UTF8ToUTF16(property_value));
property_set = true;
}
return property_set;
}
void UIElementWithMetaData::InitSources() {
if (GetLayer())
AddSource("ui/compositor/layer.h", 0);
for (ui::metadata::ClassMetaData* metadata = GetClassMetaData();
metadata != nullptr; metadata = metadata->parent_class_meta_data()) {
// If class has Metadata properties, add their sources.
if (!metadata->members().empty()) {
AddSource(metadata->file(), metadata->line());
}
}
}
ui::Layer* UIElementWithMetaData::GetLayer() const {
return nullptr;
}
} // namespace ui_devtools