[Bf-blender-cvs] [d5ae369efa3] blender-projects-basics: Initial support for reading project name from settings.json

Julian Eisel noreply at git.blender.org
Thu Sep 29 16:58:30 CEST 2022


Commit: d5ae369efa3f95bfac959dd78e7339828d11b807
Author: Julian Eisel
Date:   Thu Sep 29 16:56:43 2022 +0200
Branches: blender-projects-basics
https://developer.blender.org/rBd5ae369efa3f95bfac959dd78e7339828d11b807

Initial support for reading project name from settings.json

Adds very basic json deserializing for reading a project name from a
`.blender_project/settings.json` file. The name is displayed in the
window title.

===================================================================

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_window.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_blender_project.h b/source/blender/blenkernel/BKE_blender_project.h
index fb4ca90a184..e1bcced6cdd 100644
--- a/source/blender/blenkernel/BKE_blender_project.h
+++ b/source/blender/blenkernel/BKE_blender_project.h
@@ -38,6 +38,8 @@ BlenderProject *BKE_project_active_load_from_path(const char *path) 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
+    ATTR_NONNULL();
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/blenkernel/BKE_blender_project.hh b/source/blender/blenkernel/BKE_blender_project.hh
index 9f775009aff..221e3c34d2c 100644
--- a/source/blender/blenkernel/BKE_blender_project.hh
+++ b/source/blender/blenkernel/BKE_blender_project.hh
@@ -43,9 +43,11 @@ class BlenderProject {
 class ProjectSettings {
   /* Path to the project root using slashes in the OS native format. */
   std::string project_root_path_;
+  std::string project_name_;
 
  public:
   inline static const StringRefNull SETTINGS_DIRNAME = ".blender_project";
+  inline static const StringRefNull SETTINGS_FILENAME = "settings.json";
 
   /**
    * Initializes a blender project by creating a .blender_project directory at the given \a
@@ -67,6 +69,7 @@ class ProjectSettings {
   explicit ProjectSettings(StringRef project_root_path);
 
   auto project_root_path [[nodiscard]] () const -> StringRefNull;
+  auto project_name [[nodiscard]] () const -> StringRefNull;
 };
 
 }  // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/blender_project.cc b/source/blender/blenkernel/intern/blender_project.cc
index 51f44bcd032..5fe10df4cc9 100644
--- a/source/blender/blenkernel/intern/blender_project.cc
+++ b/source/blender/blenkernel/intern/blender_project.cc
@@ -4,10 +4,13 @@
  * \ingroup bke
  */
 
+#include <fstream>
+
 #include "BKE_blender_project.h"
 #include "BKE_blender_project.hh"
 
 #include "BLI_path_util.h"
+#include "BLI_serialize.hh"
 #include "BLI_string.h"
 
 #include "DNA_space_types.h"
@@ -15,6 +18,8 @@
 #include "BLI_fileops.h"
 #include "BLI_path_util.h"
 
+namespace serialize = blender::io::serialize;
+
 namespace blender::bke {
 
 static StringRef path_strip_trailing_native_slash(StringRef path);
@@ -102,6 +107,51 @@ static bool path_contains_project_settings(StringRef path)
   return BLI_exists(std::string(path + SEP_STR + ProjectSettings::SETTINGS_DIRNAME).c_str());
 }
 
+struct ExtractedSettings {
+  std::string project_name;
+};
+
+static std::unique_ptr<serialize::Value> read_settings_file(StringRef settings_filepath)
+{
+  std::ifstream is;
+  is.open(settings_filepath);
+  if (is.fail()) {
+    return nullptr;
+  }
+
+  serialize::JsonFormatter formatter;
+  /* Will not be a dictionary in case of error (corrupted file). */
+  std::unique_ptr<serialize::Value> deserialized_values = formatter.deserialize(is);
+  is.close();
+
+  if (deserialized_values->type() != serialize::eValueType::Dictionary) {
+    return nullptr;
+  }
+
+  return deserialized_values;
+}
+
+static std::unique_ptr<ExtractedSettings> extract_settings(
+    const serialize::DictionaryValue &dictionary)
+{
+  using namespace serialize;
+
+  std::unique_ptr extracted_settings = std::make_unique<ExtractedSettings>();
+
+  const DictionaryValue::Lookup attributes = dictionary.create_lookup();
+  const DictionaryValue::LookupValue *project_value = attributes.lookup_ptr("project");
+  BLI_assert(project_value != nullptr);
+
+  const DictionaryValue *project_dict = (*project_value)->as_dictionary_value();
+  const StringValue *project_name_value =
+      project_dict->create_lookup().lookup("name")->as_string_value();
+  if (project_name_value) {
+    extracted_settings->project_name = project_name_value->value();
+  }
+
+  return extracted_settings;
+}
+
 std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef project_path)
 {
   std::string project_path_native = project_path;
@@ -122,7 +172,21 @@ std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef proje
     return nullptr;
   }
 
-  return std::make_unique<ProjectSettings>(project_root_path);
+  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<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);
+  if (extracted_settings) {
+    loaded_settings->project_name_ = extracted_settings->project_name;
+  }
+
+  return loaded_settings;
 }
 
 StringRefNull ProjectSettings::project_root_path() const
@@ -130,6 +194,11 @@ StringRefNull ProjectSettings::project_root_path() const
   return project_root_path_;
 }
 
+StringRefNull ProjectSettings::project_name() const
+{
+  return project_name_;
+}
+
 }  // namespace blender::bke
 
 /* ---------------------------------------------------------------------- */
@@ -178,3 +247,10 @@ const char *BKE_project_root_path_get(const BlenderProject *project_handle)
       project_handle);
   return project->get_settings().project_root_path().c_str();
 }
+
+const char *BKE_project_name_get(const BlenderProject *project_handle)
+{
+  const bke::BlenderProject *project = reinterpret_cast<const bke::BlenderProject *>(
+      project_handle);
+  return project->get_settings().project_name().c_str();
+}
diff --git a/source/blender/blenkernel/intern/blender_project_test.cc b/source/blender/blenkernel/intern/blender_project_test.cc
index c804f667e99..3582bd81755 100644
--- a/source/blender/blenkernel/intern/blender_project_test.cc
+++ b/source/blender/blenkernel/intern/blender_project_test.cc
@@ -127,6 +127,7 @@ TEST_F(ProjectTest, settings_load_from_project_root_path)
     std::unique_ptr project_settings = ProjectSettings::load_from_disk(project_path);
     EXPECT_NE(project_settings, nullptr);
     EXPECT_EQ(project_settings->project_root_path(), project_path_native);
+    EXPECT_EQ(project_settings->project_name(), "");
   });
 }
 
@@ -141,6 +142,7 @@ TEST_F(ProjectTest, settings_load_from_project_settings_path)
         project_path + SEP_STR + ProjectSettings::SETTINGS_DIRNAME);
     EXPECT_NE(project_settings, nullptr);
     EXPECT_EQ(project_settings->project_root_path(), project_path_native);
+    EXPECT_EQ(project_settings->project_name(), "");
   });
 }
 
@@ -188,6 +190,7 @@ TEST_F(BlendfileProjectLoadingTest, load_blend_file)
   ::BlenderProject *svn_project = BKE_project_active_load_from_path(bfile->main->filepath);
   EXPECT_NE(svn_project, nullptr);
   EXPECT_EQ(BKE_project_active_get(), svn_project);
+  EXPECT_STREQ("Ružena", BKE_project_name_get(svn_project));
   /* Note: The project above will be freed once a different active project is set. So get the path
    * for future comparisons. */
   std::string svn_project_path = BKE_project_root_path_get(svn_project);
@@ -204,6 +207,7 @@ TEST_F(BlendfileProjectLoadingTest, load_blend_file)
   EXPECT_NE(svn_project_from_nested, nullptr);
   EXPECT_EQ(BKE_project_active_get(), svn_project_from_nested);
   EXPECT_STREQ(svn_project_path.c_str(), BKE_project_root_path_get(svn_project_from_nested));
+  EXPECT_STREQ("Ružena", BKE_project_name_get(svn_project_from_nested));
   blendfile_free();
 
   /* Check if loading a .blend that's not in the project unsets the project properly. */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 7863cc2b224..b087878819b 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -28,6 +28,7 @@
 
 #include "BLT_translation.h"
 
+#include "BKE_blender_project.h"
 #include "BKE_context.h"
 #include "BKE_global.h"
 #include "BKE_icons.h"
@@ -447,6 +448,8 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
 
 void wm_window_title(wmWindowManager *wm, wmWindow *win)
 {
+#define MAX_PROJECT_NAME_HINT (MAX_NAME + 4)
+
   if (WM_window_is_temp_screen(win)) {
     /* Nothing to do for 'temp' windows,
      * because #WM_window_open always sets window title. */
@@ -455,14 +458,23 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
     /* this is set to 1 if you don't have startup.blend open */
     const char *blendfile_path = BKE_main_blendfile_path_from_global();
     if (blendfile_path[0] != '\0') {
-      char str[sizeof(((Main *)NULL)->filepath) + 24];
+      char project_name_hint[MAX_PROJECT_NAME_HINT] = "";
+      char str[sizeof(((Main *)NULL)->filepath) + sizeof(project_name_hint) + 24];
+
       struct BlenderProject *project = CTX_wm_project();
+      if (project) {
+        const char *name = BKE_project_name_get(project);
+        BLI_snprintf(project_name_hint,
+                     sizeof(project_name_hint),
+                     "%s - ",
+                     (name && name[0]) ? name : IFACE_("Unnamed project"));
+      }
 
       BLI_snprintf(str,
                    sizeof(str),
                    "Blender%s [%s%s%s]",
                    wm->file_saved ? "" : "*",
-                   project ? IFACE_("Has Project - ") : "",
+                   project_name_hint,
                    blendfile_path,
                    G_MAIN->recovered ? " (Recovered)" : "");
       GHOST_SetTitle(win->ghostwin, str);
@@ -476,6 +488,8 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
      * terminate request (e.g. OS Shortcut Alt+F4, Command+Q, (...), or session end). */
     GHOST_SetWindowModifiedState(win->ghostwin, (bool)!wm->file_saved);
   }
+
+#undef MAX_PROJECT_NAME_HINT
 }
 
 void WM_window_set_dpi(const wmWindow *win)



More information about the Bf-blender-cvs mailing list