[Bf-blender-cvs] [cd15fbbed62] blender-projects-basics: Support saving project settings to .blender_project/settings.json
Julian Eisel
noreply at git.blender.org
Thu Oct 6 15:58:51 CEST 2022
Commit: cd15fbbed622873e9347b48b36931f99c1c6def5
Author: Julian Eisel
Date: Thu Oct 6 15:51:10 2022 +0200
Branches: blender-projects-basics
https://developer.blender.org/rBcd15fbbed622873e9347b48b36931f99c1c6def5
Support saving project settings to .blender_project/settings.json
===================================================================
M release/scripts/startup/bl_ui/space_project_settings.py
M source/blender/blenkernel/BKE_blender_project.h
M source/blender/blenkernel/BKE_blender_project.hh
M source/blender/blenkernel/intern/blender_project.cc
M source/blender/blenkernel/intern/blender_project_test.cc
M source/blender/windowmanager/intern/wm_files.c
M source/blender/windowmanager/intern/wm_operators.c
M source/blender/windowmanager/wm_files.h
===================================================================
diff --git a/release/scripts/startup/bl_ui/space_project_settings.py b/release/scripts/startup/bl_ui/space_project_settings.py
index 9fa42334e87..b2a543e9e07 100644
--- a/release/scripts/startup/bl_ui/space_project_settings.py
+++ b/release/scripts/startup/bl_ui/space_project_settings.py
@@ -19,8 +19,8 @@ class PROJECTSETTINGS_HT_header(Header):
# Show '*' to let users know the settings have been modified.
# TODO, wrong operator
layout.operator(
- "wm.save_userpref",
- text=iface_("Save Project Settings") + (" *" if is_dirty else ""),
+ "wm.save_project_settings",
+ text=iface_("Save Settings") + (" *" if is_dirty else ""),
translate=False,
)
diff --git a/source/blender/blenkernel/BKE_blender_project.h b/source/blender/blenkernel/BKE_blender_project.h
index e1bcced6cdd..eff87d4aef5 100644
--- a/source/blender/blenkernel/BKE_blender_project.h
+++ b/source/blender/blenkernel/BKE_blender_project.h
@@ -36,6 +36,8 @@ void BKE_project_active_unset(void);
*/
BlenderProject *BKE_project_active_load_from_path(const char *path) ATTR_NONNULL();
+bool BKE_project_settings_save(const BlenderProject *project) ATTR_NONNULL();
+
const char *BKE_project_root_path_get(const BlenderProject *project) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
const char *BKE_project_name_get(const BlenderProject *project) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/blenkernel/BKE_blender_project.hh b/source/blender/blenkernel/BKE_blender_project.hh
index 221e3c34d2c..bd1a232b592 100644
--- a/source/blender/blenkernel/BKE_blender_project.hh
+++ b/source/blender/blenkernel/BKE_blender_project.hh
@@ -10,6 +10,10 @@
#include "BLI_string_ref.hh"
+namespace blender::io::serialize {
+class DictionaryValue;
+}
+
namespace blender::bke {
class ProjectSettings;
@@ -60,16 +64,27 @@ class ProjectSettings {
/**
* Read project settings from the given \a project_path, which may be either a project root
* directory or the .blender_project directory.
- * Both Unix and Windows style slashes are allowed.
+ * Both Unix and Windows style slashes are allowed. Path is expected to be normalized.
* \return The read project settings or null in case of failure.
*/
static auto load_from_disk [[nodiscard]] (StringRef project_path)
-> std::unique_ptr<ProjectSettings>;
+ /**
+ * Write project settings to the given \a project_path, which may be either a project root
+ * directory or the .blender_project directory. The .blender_project directory must exist.
+ * Both Unix and Windows style slashes are allowed. Path is expected to be normalized.
+ * \return True on success. If the .blender_project directory doesn't exist, that's treated as
+ * failure.
+ */
+ auto save_to_disk(StringRef project_path) const -> bool;
explicit ProjectSettings(StringRef project_root_path);
auto project_root_path [[nodiscard]] () const -> StringRefNull;
auto project_name [[nodiscard]] () const -> StringRefNull;
+
+ private:
+ auto to_dictionary() const -> std::unique_ptr<io::serialize::DictionaryValue>;
};
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/blender_project.cc b/source/blender/blenkernel/intern/blender_project.cc
index 5fe10df4cc9..99d92138ca5 100644
--- a/source/blender/blenkernel/intern/blender_project.cc
+++ b/source/blender/blenkernel/intern/blender_project.cc
@@ -152,36 +152,55 @@ static std::unique_ptr<ExtractedSettings> extract_settings(
return extracted_settings;
}
-std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef project_path)
+struct ResolvedPaths {
+ std::string settings_filepath;
+ std::string project_root_path;
+};
+
+/**
+ * Returned paths can be assumed to use native slashes.
+ */
+static ResolvedPaths resolve_paths_from_project_path(StringRef project_path)
{
std::string project_path_native = project_path;
BLI_path_slash_native(project_path_native.data());
- if (!BLI_exists(project_path_native.c_str())) {
- return nullptr;
- }
-
- StringRef project_root_path = project_path_native;
+ ResolvedPaths resolved_paths{};
const StringRef path_no_trailing_slashes = path_strip_trailing_native_slash(project_path_native);
- if (path_no_trailing_slashes.endswith(SETTINGS_DIRNAME)) {
- project_root_path = StringRef(project_path_native).drop_suffix(SETTINGS_DIRNAME.size() + 1);
+ if (path_no_trailing_slashes.endswith(ProjectSettings::SETTINGS_DIRNAME)) {
+ resolved_paths.project_root_path =
+ StringRef(path_no_trailing_slashes).drop_suffix(ProjectSettings::SETTINGS_DIRNAME.size());
+ }
+ else {
+ resolved_paths.project_root_path = std::string(path_no_trailing_slashes) + SEP;
}
+ resolved_paths.settings_filepath = resolved_paths.project_root_path +
+ ProjectSettings::SETTINGS_DIRNAME + SEP +
+ ProjectSettings::SETTINGS_FILENAME;
+
+ return resolved_paths;
+}
- if (!path_contains_project_settings(project_root_path)) {
+std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef project_path)
+{
+ ResolvedPaths paths = resolve_paths_from_project_path(project_path);
+
+ if (!BLI_exists(paths.project_root_path.c_str())) {
+ return nullptr;
+ }
+ if (!path_contains_project_settings(paths.project_root_path.c_str())) {
return nullptr;
}
- std::string settings_filepath = project_path_native + SEP + SETTINGS_DIRNAME + SEP +
- SETTINGS_FILENAME;
- std::unique_ptr<serialize::Value> values = read_settings_file(settings_filepath);
+ std::unique_ptr<serialize::Value> values = read_settings_file(paths.settings_filepath);
std::unique_ptr<ExtractedSettings> extracted_settings = nullptr;
if (values) {
BLI_assert(values->as_dictionary_value() != nullptr);
extracted_settings = extract_settings(*values->as_dictionary_value());
}
- std::unique_ptr loaded_settings = std::make_unique<ProjectSettings>(project_root_path);
+ std::unique_ptr loaded_settings = std::make_unique<ProjectSettings>(paths.project_root_path);
if (extracted_settings) {
loaded_settings->project_name_ = extracted_settings->project_name;
}
@@ -189,6 +208,50 @@ std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef proje
return loaded_settings;
}
+std::unique_ptr<serialize::DictionaryValue> ProjectSettings::to_dictionary() const
+{
+ using namespace serialize;
+
+ std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &root_attributes = root->elements();
+ std::unique_ptr<DictionaryValue> project_dict = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &project_attributes = project_dict->elements();
+ project_attributes.append_as("name", new StringValue(project_name_));
+ root_attributes.append_as("project", std::move(project_dict));
+
+ return root;
+}
+
+static void write_settings_file(StringRef settings_filepath,
+ std::unique_ptr<serialize::DictionaryValue> dictionary)
+{
+ using namespace serialize;
+
+ JsonFormatter formatter;
+
+ std::ofstream os;
+ os.open(settings_filepath, std::ios::out | std::ios::trunc);
+ formatter.serialize(os, *dictionary);
+ os.close();
+}
+
+bool ProjectSettings::save_to_disk(StringRef project_path) const
+{
+ ResolvedPaths paths = resolve_paths_from_project_path(project_path);
+
+ if (!BLI_exists(paths.project_root_path.c_str())) {
+ return false;
+ }
+ if (!path_contains_project_settings(paths.project_root_path.c_str())) {
+ return false;
+ }
+
+ std::unique_ptr settings_as_dict = to_dictionary();
+ write_settings_file(paths.settings_filepath, std::move(settings_as_dict));
+
+ return true;
+}
+
StringRefNull ProjectSettings::project_root_path() const
{
return project_root_path_;
@@ -241,6 +304,14 @@ BlenderProject *BKE_project_active_load_from_path(const char *path)
return BKE_project_active_get();
}
+bool BKE_project_settings_save(const BlenderProject *project_handle)
+{
+ const bke::BlenderProject *project = reinterpret_cast<const bke::BlenderProject *>(
+ project_handle);
+ const bke::ProjectSettings &settings = project->get_settings();
+ return settings.save_to_disk(settings.project_root_path());
+}
+
const char *BKE_project_root_path_get(const BlenderProject *project_handle)
{
const bke::BlenderProject *project = reinterpret_cast<const bke::BlenderProject *>(
diff --git a/source/blender/blenkernel/intern/blender_project_test.cc b/source/blender/blenkernel/intern/blender_project_test.cc
index 3582bd81755..cb3c56070bb 100644
--- a/source/blender/blenkernel/intern/blender_project_test.cc
+++ b/source/blender/blenkernel/intern/blender_project_test.cc
@@ -19,6 +19,12 @@
namespace blender::bke::tests {
+struct SVNFiles {
+ const std::string svn_root = blender::tests::flags_test_asset_dir();
+ const std::string project_root_rel = "blender_project/the_project";
+ const std::string project_root = svn_root + "/blender_project/the_project";
+};
+
class ProjectTest : public testing::Test {
/* RAII helper to delete the created directories reliably after testing or on errors. */
struct ProjectDirectoryRAIIWrapper {
@@ -36,6 +42,9 @@ class ProjectTest : public testing::Test {
native_project_path_ = project_path;
BLI_path_slash_native(native_project_path_.data());
+ if (native_project_path_.back() != SEP) {
+ native_project_path_ += SEP;
+ }
/** Assert would be preferable but that would only run in debug builds, and #ASSERT_TRUE()
* doesn't support printing a message. */
@@ -139,18 +148,42 @@ TEST_F(ProjectTest, settings_load_from_project_settings_path)
ProjectSettings::create_settings_directory(project_path);
std::unique_ptr project_settings = ProjectSettings::load_from_disk(
- project_path + SEP_STR + ProjectSettings::SETTINGS_DIRNAME);
+ project_path + (ELEM(project_path.back(), SEP, ALTSEP) ? "" : SEP_STR) +
+ ProjectSettings::SETTINGS_DIRNAME);
EXPECT_NE(project_settings, nullptr);
EXPECT_EQ(project_settings->project_
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list