mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-21 17:45:25 -04:00
335 lines
11 KiB
C++
335 lines
11 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
|
* reserved. This project is released under the MIT License.
|
|
*/
|
|
#include "GDCore/Project/PropertyFolderOrProperty.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "GDCore/Project/NamedPropertyDescriptor.h"
|
|
#include "GDCore/Project/PropertiesContainer.h"
|
|
#include "GDCore/Serialization/SerializerElement.h"
|
|
#include "GDCore/Tools/Log.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace gd {
|
|
|
|
PropertyFolderOrProperty PropertyFolderOrProperty::badPropertyFolderOrProperty;
|
|
gd::String PropertyFolderOrProperty::emptyGroupName;
|
|
|
|
PropertyFolderOrProperty::PropertyFolderOrProperty()
|
|
: folderName("__NULL"), property(nullptr) {}
|
|
PropertyFolderOrProperty::PropertyFolderOrProperty(
|
|
gd::String folderName_, PropertyFolderOrProperty *parent_)
|
|
: folderName(folderName_), parent(parent_), property(nullptr) {}
|
|
PropertyFolderOrProperty::PropertyFolderOrProperty(
|
|
gd::NamedPropertyDescriptor *property_, PropertyFolderOrProperty *parent_)
|
|
: property(property_), parent(parent_) {}
|
|
PropertyFolderOrProperty::~PropertyFolderOrProperty() {}
|
|
|
|
bool PropertyFolderOrProperty::HasPropertyNamed(const gd::String &name) {
|
|
if (IsFolder()) {
|
|
return std::any_of(children.begin(), children.end(),
|
|
[&name](std::unique_ptr<gd::PropertyFolderOrProperty>
|
|
&propertyFolderOrProperty) {
|
|
return propertyFolderOrProperty->HasPropertyNamed(
|
|
name);
|
|
});
|
|
}
|
|
if (!property)
|
|
return false;
|
|
return property->GetName() == name;
|
|
}
|
|
|
|
PropertyFolderOrProperty &
|
|
PropertyFolderOrProperty::GetOrCreateChildFolder(const gd::String &name) {
|
|
if (!IsFolder()) {
|
|
LogError("Try to create of a folder '" + name + "' inside a property");
|
|
return gd::PropertyFolderOrProperty::badPropertyFolderOrProperty;
|
|
}
|
|
for (auto &&child : children) {
|
|
if (child->IsFolder() && child->folderName == name) {
|
|
return *child;
|
|
}
|
|
}
|
|
return InsertNewFolder(name, GetChildrenCount());
|
|
}
|
|
|
|
PropertyFolderOrProperty &
|
|
PropertyFolderOrProperty::GetPropertyNamed(const gd::String &name) {
|
|
if (property && property->GetName() == name) {
|
|
return *this;
|
|
}
|
|
if (IsFolder()) {
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
PropertyFolderOrProperty &foundInChild =
|
|
children[j]->GetPropertyNamed(name);
|
|
if (&(foundInChild) != &badPropertyFolderOrProperty) {
|
|
return foundInChild;
|
|
}
|
|
}
|
|
}
|
|
return badPropertyFolderOrProperty;
|
|
}
|
|
|
|
void PropertyFolderOrProperty::SetFolderName(const gd::String &name) {
|
|
if (!IsFolder())
|
|
return;
|
|
folderName = name;
|
|
if (parent && !parent->parent) {
|
|
SetGroupNameOfAllProperties(name);
|
|
}
|
|
}
|
|
|
|
void PropertyFolderOrProperty::SetGroupNameOfAllProperties(
|
|
const gd::String &groupName) {
|
|
if (IsFolder()) {
|
|
for (auto &&child : children) {
|
|
child->SetGroupNameOfAllProperties(groupName);
|
|
}
|
|
} else {
|
|
property->SetGroup(groupName);
|
|
}
|
|
}
|
|
|
|
const gd::String &PropertyFolderOrProperty::GetGroupName() {
|
|
auto *groupFolder = this;
|
|
auto *rootFolder = parent;
|
|
if (!rootFolder) {
|
|
return gd::PropertyFolderOrProperty::emptyGroupName;
|
|
}
|
|
while (rootFolder->parent) {
|
|
groupFolder = rootFolder;
|
|
rootFolder = rootFolder->parent;
|
|
}
|
|
return groupFolder->GetFolderName();
|
|
}
|
|
|
|
void PropertyFolderOrProperty::UpdateGroupNameOfAllProperties() {
|
|
if (parent) {
|
|
SetGroupNameOfAllProperties(GetGroupName());
|
|
}
|
|
else {
|
|
// This is a root folder, the group is not the same for all children.
|
|
for (auto &&child : children) {
|
|
child->SetGroupNameOfAllProperties(child->GetGroupName());
|
|
}
|
|
}
|
|
}
|
|
|
|
PropertyFolderOrProperty &
|
|
PropertyFolderOrProperty::GetChildAt(std::size_t index) {
|
|
if (index >= children.size())
|
|
return badPropertyFolderOrProperty;
|
|
return *children[index];
|
|
}
|
|
const PropertyFolderOrProperty &
|
|
PropertyFolderOrProperty::GetChildAt(std::size_t index) const {
|
|
if (index >= children.size())
|
|
return badPropertyFolderOrProperty;
|
|
return *children[index];
|
|
}
|
|
PropertyFolderOrProperty &
|
|
PropertyFolderOrProperty::GetPropertyChild(const gd::String &name) {
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
if (!children[j]->IsFolder()) {
|
|
if (children[j]->GetProperty().GetName() == name)
|
|
return *children[j];
|
|
};
|
|
}
|
|
return badPropertyFolderOrProperty;
|
|
}
|
|
|
|
void PropertyFolderOrProperty::InsertProperty(
|
|
gd::NamedPropertyDescriptor *insertedProperty, std::size_t position) {
|
|
insertedProperty->SetGroup(GetGroupName());
|
|
auto propertyFolderOrProperty =
|
|
gd::make_unique<PropertyFolderOrProperty>(insertedProperty, this);
|
|
if (position < children.size()) {
|
|
children.insert(children.begin() + position,
|
|
std::move(propertyFolderOrProperty));
|
|
} else {
|
|
children.push_back(std::move(propertyFolderOrProperty));
|
|
}
|
|
}
|
|
|
|
std::size_t PropertyFolderOrProperty::GetChildPosition(
|
|
const PropertyFolderOrProperty &child) const {
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
if (children[j].get() == &child)
|
|
return j;
|
|
}
|
|
return gd::String::npos;
|
|
}
|
|
|
|
PropertyFolderOrProperty &
|
|
PropertyFolderOrProperty::InsertNewFolder(const gd::String &newFolderName,
|
|
std::size_t position) {
|
|
auto newFolderPtr =
|
|
gd::make_unique<PropertyFolderOrProperty>(newFolderName, this);
|
|
gd::PropertyFolderOrProperty &newFolder = *(*(children.insert(
|
|
position < children.size() ? children.begin() + position : children.end(),
|
|
std::move(newFolderPtr))));
|
|
return newFolder;
|
|
};
|
|
|
|
void PropertyFolderOrProperty::RemoveRecursivelyPropertyNamed(
|
|
const gd::String &name) {
|
|
if (IsFolder()) {
|
|
children.erase(
|
|
std::remove_if(
|
|
children.begin(), children.end(),
|
|
[&name](std::unique_ptr<gd::PropertyFolderOrProperty>
|
|
&propertyFolderOrProperty) {
|
|
return !propertyFolderOrProperty->IsFolder() &&
|
|
propertyFolderOrProperty->GetProperty().GetName() == name;
|
|
}),
|
|
children.end());
|
|
for (auto &it : children) {
|
|
it->RemoveRecursivelyPropertyNamed(name);
|
|
}
|
|
}
|
|
};
|
|
|
|
void PropertyFolderOrProperty::Clear() {
|
|
if (IsFolder()) {
|
|
for (auto &it : children) {
|
|
it->Clear();
|
|
}
|
|
children.clear();
|
|
}
|
|
};
|
|
|
|
bool PropertyFolderOrProperty::IsADescendantOf(
|
|
const PropertyFolderOrProperty &otherPropertyFolderOrProperty) {
|
|
if (parent == nullptr)
|
|
return false;
|
|
if (&(*parent) == &otherPropertyFolderOrProperty)
|
|
return true;
|
|
return parent->IsADescendantOf(otherPropertyFolderOrProperty);
|
|
}
|
|
|
|
void PropertyFolderOrProperty::MoveChild(std::size_t oldIndex,
|
|
std::size_t newIndex) {
|
|
if (!IsFolder())
|
|
return;
|
|
if (oldIndex >= children.size() || newIndex >= children.size())
|
|
return;
|
|
|
|
std::unique_ptr<gd::PropertyFolderOrProperty> propertyFolderOrProperty =
|
|
std::move(children[oldIndex]);
|
|
children.erase(children.begin() + oldIndex);
|
|
children.insert(children.begin() + newIndex,
|
|
std::move(propertyFolderOrProperty));
|
|
}
|
|
|
|
void PropertyFolderOrProperty::RemoveFolderChild(
|
|
const PropertyFolderOrProperty &childToRemove) {
|
|
if (!IsFolder() || !childToRemove.IsFolder() ||
|
|
childToRemove.GetChildrenCount() > 0) {
|
|
return;
|
|
}
|
|
std::vector<std::unique_ptr<gd::PropertyFolderOrProperty>>::iterator it =
|
|
find_if(children.begin(), children.end(),
|
|
[&childToRemove](
|
|
std::unique_ptr<gd::PropertyFolderOrProperty> &child) {
|
|
return child.get() == &childToRemove;
|
|
});
|
|
if (it == children.end())
|
|
return;
|
|
|
|
children.erase(it);
|
|
}
|
|
|
|
void PropertyFolderOrProperty::MovePropertyFolderOrPropertyToAnotherFolder(
|
|
gd::PropertyFolderOrProperty &propertyFolderOrProperty,
|
|
gd::PropertyFolderOrProperty &newParentFolder, std::size_t newPosition) {
|
|
if (!newParentFolder.IsFolder())
|
|
return;
|
|
if (newParentFolder.IsADescendantOf(propertyFolderOrProperty))
|
|
return;
|
|
|
|
std::vector<std::unique_ptr<gd::PropertyFolderOrProperty>>::iterator it =
|
|
find_if(children.begin(), children.end(),
|
|
[&propertyFolderOrProperty](
|
|
std::unique_ptr<gd::PropertyFolderOrProperty>
|
|
&childPropertyFolderOrProperty) {
|
|
return childPropertyFolderOrProperty.get() ==
|
|
&propertyFolderOrProperty;
|
|
});
|
|
if (it == children.end())
|
|
return;
|
|
|
|
std::unique_ptr<gd::PropertyFolderOrProperty> propertyFolderOrPropertyPtr =
|
|
std::move(*it);
|
|
children.erase(it);
|
|
|
|
propertyFolderOrPropertyPtr->parent = &newParentFolder;
|
|
propertyFolderOrPropertyPtr->SetGroupNameOfAllProperties(
|
|
newParentFolder.IsRootFolder() && propertyFolderOrPropertyPtr->IsFolder()
|
|
? propertyFolderOrPropertyPtr->GetFolderName()
|
|
: newParentFolder.GetGroupName());
|
|
|
|
newParentFolder.children.insert(newPosition < newParentFolder.children.size()
|
|
? newParentFolder.children.begin() +
|
|
newPosition
|
|
: newParentFolder.children.end(),
|
|
std::move(propertyFolderOrPropertyPtr));
|
|
}
|
|
|
|
void PropertyFolderOrProperty::SerializeTo(SerializerElement &element) const {
|
|
if (IsFolder()) {
|
|
element.SetAttribute("folderName", GetFolderName());
|
|
if (children.size() > 0) {
|
|
SerializerElement &childrenElement = element.AddChild("children");
|
|
childrenElement.ConsiderAsArrayOf("propertyFolderOrProperty");
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
children[j]->SerializeTo(
|
|
childrenElement.AddChild("propertyFolderOrProperty"));
|
|
}
|
|
}
|
|
} else {
|
|
element.SetAttribute("propertyName", GetProperty().GetName());
|
|
}
|
|
}
|
|
|
|
void PropertyFolderOrProperty::UnserializeFrom(
|
|
gd::Project &project, const SerializerElement &element,
|
|
gd::PropertiesContainer &propertiesContainer) {
|
|
children.clear();
|
|
gd::String potentialFolderName = element.GetStringAttribute("folderName", "");
|
|
|
|
if (!potentialFolderName.empty()) {
|
|
property = nullptr;
|
|
folderName = potentialFolderName;
|
|
|
|
if (element.HasChild("children")) {
|
|
const SerializerElement &childrenElements =
|
|
element.GetChild("children", 0);
|
|
childrenElements.ConsiderAsArrayOf("propertyFolderOrProperty");
|
|
for (std::size_t i = 0; i < childrenElements.GetChildrenCount(); ++i) {
|
|
std::unique_ptr<PropertyFolderOrProperty>
|
|
childPropertyFolderOrProperty =
|
|
make_unique<PropertyFolderOrProperty>();
|
|
childPropertyFolderOrProperty->UnserializeFrom(
|
|
project, childrenElements.GetChild(i), propertiesContainer);
|
|
childPropertyFolderOrProperty->parent = this;
|
|
children.push_back(std::move(childPropertyFolderOrProperty));
|
|
}
|
|
}
|
|
} else {
|
|
folderName = "";
|
|
gd::String propertyName = element.GetStringAttribute("propertyName");
|
|
if (propertiesContainer.Has(propertyName)) {
|
|
property = &propertiesContainer.Get(propertyName);
|
|
} else {
|
|
gd::LogError("Property with name " + propertyName +
|
|
" not found in properties container.");
|
|
property = nullptr;
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace gd
|