WIP: Basic Blender Project Support (experimental feature) #107655
|
@ -13,11 +13,13 @@ class PROJECTSETTINGS_HT_header(Header):
|
|||
|
||||
@staticmethod
|
||||
def draw_buttons(layout, context):
|
||||
project = context.project
|
||||
|
||||
layout.operator_context = 'EXEC_AREA'
|
||||
is_dirty = True
|
||||
|
||||
is_dirty = project and project.is_dirty
|
||||
|
||||
# Show '*' to let users know the settings have been modified.
|
||||
# TODO, wrong operator
|
||||
layout.operator(
|
||||
"wm.save_project_settings",
|
||||
text=iface_("Save Settings") + (" *" if is_dirty else ""),
|
||||
|
|
|
@ -46,6 +46,8 @@ const char *BKE_project_root_path_get(const BlenderProject *project) ATTR_WARN_U
|
|||
void BKE_project_name_set(const BlenderProject *project_handle, const char *name) ATTR_NONNULL();
|
||||
const char *BKE_project_name_get(const BlenderProject *project) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
bool BKE_project_has_unsaved_changes(const BlenderProject *project) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ class ProjectSettings {
|
|||
/* Path to the project root using slashes in the OS native format. */
|
||||
std::string project_root_path_;
|
||||
std::string project_name_;
|
||||
bool has_unsaved_changes_ = false;
|
||||
|
||||
public:
|
||||
inline static const StringRefNull SETTINGS_DIRNAME = ".blender_project";
|
||||
|
@ -76,13 +77,14 @@ class ProjectSettings {
|
|||
* \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;
|
||||
auto save_to_disk(StringRef project_path) -> bool;
|
||||
|
||||
explicit ProjectSettings(StringRef project_root_path);
|
||||
|
||||
auto project_root_path [[nodiscard]] () const -> StringRefNull;
|
||||
void project_name(StringRef new_name);
|
||||
auto project_name [[nodiscard]] () const -> StringRefNull;
|
||||
auto has_unsaved_changes [[nodiscard]] () const -> bool;
|
||||
|
||||
private:
|
||||
auto to_dictionary() const -> std::unique_ptr<io::serialize::DictionaryValue>;
|
||||
|
|
|
@ -235,7 +235,7 @@ static void write_settings_file(StringRef settings_filepath,
|
|||
os.close();
|
||||
}
|
||||
|
||||
bool ProjectSettings::save_to_disk(StringRef project_path) const
|
||||
bool ProjectSettings::save_to_disk(StringRef project_path)
|
||||
{
|
||||
ResolvedPaths paths = resolve_paths_from_project_path(project_path);
|
||||
|
||||
|
@ -249,6 +249,8 @@ bool ProjectSettings::save_to_disk(StringRef project_path) const
|
|||
std::unique_ptr settings_as_dict = to_dictionary();
|
||||
write_settings_file(paths.settings_filepath, std::move(settings_as_dict));
|
||||
|
||||
has_unsaved_changes_ = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -260,6 +262,7 @@ StringRefNull ProjectSettings::project_root_path() const
|
|||
void ProjectSettings::project_name(StringRef new_name)
|
||||
{
|
||||
project_name_ = new_name;
|
||||
has_unsaved_changes_ = true;
|
||||
}
|
||||
|
||||
StringRefNull ProjectSettings::project_name() const
|
||||
|
@ -267,6 +270,11 @@ StringRefNull ProjectSettings::project_name() const
|
|||
return project_name_;
|
||||
}
|
||||
|
||||
bool ProjectSettings::has_unsaved_changes() const
|
||||
{
|
||||
return has_unsaved_changes_;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -313,7 +321,7 @@ 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();
|
||||
bke::ProjectSettings &settings = project->get_settings();
|
||||
return settings.save_to_disk(settings.project_root_path());
|
||||
}
|
||||
|
||||
|
@ -337,3 +345,11 @@ const char *BKE_project_name_get(const BlenderProject *project_handle)
|
|||
project_handle);
|
||||
return project->get_settings().project_name().c_str();
|
||||
}
|
||||
|
||||
bool BKE_project_has_unsaved_changes(const BlenderProject *project_handle)
|
||||
{
|
||||
const bke::BlenderProject *project = reinterpret_cast<const bke::BlenderProject *>(
|
||||
project_handle);
|
||||
const bke::ProjectSettings &settings = project->get_settings();
|
||||
return settings.has_unsaved_changes();
|
||||
}
|
||||
|
|
|
@ -185,6 +185,34 @@ TEST_F(ProjectTest, settings_json_write)
|
|||
});
|
||||
}
|
||||
|
||||
TEST_F(ProjectTest, settings_read_change_write)
|
||||
{
|
||||
SVNFiles svn_files{};
|
||||
std::unique_ptr from_project_settings = ProjectSettings::load_from_disk(svn_files.project_root);
|
||||
|
||||
EXPECT_FALSE(from_project_settings->has_unsaved_changes());
|
||||
|
||||
/* Take the settings read from the SVN files and write it to /tmp/ projects. */
|
||||
test_foreach_project_path(
|
||||
[&from_project_settings](StringRefNull to_project_path, StringRefNull) {
|
||||
ProjectSettings::create_settings_directory(to_project_path);
|
||||
|
||||
from_project_settings->project_name("новый");
|
||||
EXPECT_TRUE(from_project_settings->has_unsaved_changes());
|
||||
|
||||
if (!from_project_settings->save_to_disk(to_project_path)) {
|
||||
FAIL();
|
||||
}
|
||||
EXPECT_FALSE(from_project_settings->has_unsaved_changes());
|
||||
|
||||
/* Now check if the settings written to disk match the expectations. */
|
||||
std::unique_ptr written_settings = ProjectSettings::load_from_disk(to_project_path);
|
||||
EXPECT_NE(written_settings, nullptr);
|
||||
EXPECT_EQ(written_settings->project_name(), "новый");
|
||||
EXPECT_FALSE(from_project_settings->has_unsaved_changes());
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ProjectTest, project_root_path_find_from_path)
|
||||
{
|
||||
/* Test the temporarily created directories with their various path formats. */
|
||||
|
|
|
@ -92,6 +92,16 @@ static int rna_BlenderProject_root_path_editable(PointerRNA *UNUSED(ptr), const
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool rna_BlenderProject_is_dirty_get(PointerRNA *ptr)
|
||||
{
|
||||
const BlenderProject *project = ptr->data;
|
||||
if (!project) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return BKE_project_has_unsaved_changes(project);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void RNA_def_blender_project(BlenderRNA *brna)
|
||||
|
@ -117,6 +127,14 @@ void RNA_def_blender_project(BlenderRNA *brna)
|
|||
"rna_BlenderProject_root_path_set");
|
||||
RNA_def_property_editable_func(prop, "rna_BlenderProject_root_path_editable");
|
||||
RNA_def_property_ui_text(prop, "Location", "The location of the project on disk");
|
||||
|
||||
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_BlenderProject_is_dirty_get", NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Dirty",
|
||||
"Project settings have changed since read from disk. Save the settings to keep them");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue