From dea0f1638b12b034b64a604fcea87650ec7d0608 Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 10 Dec 2021 14:59:34 +0000 Subject: [PATCH] Rename ValueWithDefault -> ValueTreePropertyWithDefault and store default value in shared Value object to propagate changes --- .../juce_data_structures.cpp | 5 +- .../juce_data_structures.h | 2 +- .../juce_ValueTreePropertyWithDefault.h | 293 ++++++++++++++++++ ...uce_ValueTreePropertyWithDefault_test.cpp} | 48 ++- .../values/juce_ValueWithDefault.h | 244 --------------- 5 files changed, 320 insertions(+), 272 deletions(-) create mode 100644 modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h rename modules/juce_data_structures/values/{juce_ValueWithDefault.cpp => juce_ValueTreePropertyWithDefault_test.cpp} (55%) delete mode 100644 modules/juce_data_structures/values/juce_ValueWithDefault.h diff --git a/modules/juce_data_structures/juce_data_structures.cpp b/modules/juce_data_structures/juce_data_structures.cpp index 9ad4bbc618..a93db46f0f 100644 --- a/modules/juce_data_structures/juce_data_structures.cpp +++ b/modules/juce_data_structures/juce_data_structures.cpp @@ -38,7 +38,10 @@ #include "values/juce_ValueTree.cpp" #include "values/juce_ValueTreeSynchroniser.cpp" #include "values/juce_CachedValue.cpp" -#include "values/juce_ValueWithDefault.cpp" #include "undomanager/juce_UndoManager.cpp" #include "app_properties/juce_ApplicationProperties.cpp" #include "app_properties/juce_PropertiesFile.cpp" + +#if JUCE_UNIT_TESTS + #include "values/juce_ValueTreePropertyWithDefault_test.cpp" +#endif diff --git a/modules/juce_data_structures/juce_data_structures.h b/modules/juce_data_structures/juce_data_structures.h index 5f05f44f25..23f29894d1 100644 --- a/modules/juce_data_structures/juce_data_structures.h +++ b/modules/juce_data_structures/juce_data_structures.h @@ -61,6 +61,6 @@ #include "values/juce_ValueTree.h" #include "values/juce_ValueTreeSynchroniser.h" #include "values/juce_CachedValue.h" -#include "values/juce_ValueWithDefault.h" +#include "values/juce_ValueTreePropertyWithDefault.h" #include "app_properties/juce_PropertiesFile.h" #include "app_properties/juce_ApplicationProperties.h" diff --git a/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h b/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h new file mode 100644 index 0000000000..fc6d07897e --- /dev/null +++ b/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h @@ -0,0 +1,293 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 6 End-User License + Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). + + End User License Agreement: www.juce.com/juce-6-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + This class acts as a wrapper around a property inside a ValueTree. + + If the property inside the ValueTree is missing it will return a default value, + which can be specified in the constructor or by calling setDefault(). + + @tags{DataStructures} +*/ +class JUCE_API ValueTreePropertyWithDefault : private Value::Listener +{ +public: + //============================================================================== + /** Creates an uninitialised ValueTreePropertyWithDefault object. + + Initialise it using one of the referTo() methods. + */ + ValueTreePropertyWithDefault() = default; + + /** Creates a ValueTreePropertyWithDefault object for the specified property. + + The default value will be an empty var. + */ + ValueTreePropertyWithDefault (ValueTree& tree, + const Identifier& propertyID, + UndoManager* um) + { + referTo (tree, propertyID, um); + } + + /** Creates an ValueTreePropertyWithDefault object for the specified property. + + The default value will be defaultToUse. + */ + ValueTreePropertyWithDefault (ValueTree& tree, + const Identifier& propertyID, + UndoManager* um, + var defaultToUse) + { + referTo (tree, propertyID, um, defaultToUse); + } + + /** Creates a ValueTreePropertyWithDefault object for the specified property. + + The default value will be defaultToUse. + + Use this constructor if the underlying var object being controlled is an array and + it will handle the conversion to/from a delimited String that can be written to + XML format. + */ + ValueTreePropertyWithDefault (ValueTree& tree, + const Identifier& propertyID, + UndoManager* um, + var defaultToUse, + StringRef arrayDelimiter) + { + referTo (tree, propertyID, um, defaultToUse, arrayDelimiter); + } + + /** Creates a ValueTreePropertyWithDefault object from another ValueTreePropertyWithDefault object. */ + ValueTreePropertyWithDefault (const ValueTreePropertyWithDefault& other) + { + referToWithDefault (other.targetTree, + other.targetProperty, + other.undoManager, + other.defaultValue, + other.delimiter); + } + + /** Destructor. */ + ~ValueTreePropertyWithDefault() override + { + defaultValue.removeListener (this); + } + + //============================================================================== + /** Returns the current value of the property. + + If the property does not exist this returns the default value. + */ + var get() const noexcept + { + if (isUsingDefault()) + return defaultValue; + + if (delimiter.isNotEmpty()) + return delimitedStringToVarArray (targetTree[targetProperty].toString()); + + return targetTree[targetProperty]; + } + + /** Returns the current property as a Value object. */ + Value getPropertyAsValue() { return targetTree.getPropertyAsValue (targetProperty, undoManager); } + + /** Returns the current default value. */ + var getDefault() const { return defaultValue; } + + /** Sets the default value to a new var. */ + void setDefault (const var& newDefault) { defaultValue = newDefault; } + + /** Returns true if the property does not exist in the referenced ValueTree. */ + bool isUsingDefault() const { return ! targetTree.hasProperty (targetProperty); } + + /** Removes the property from the referenced ValueTree. */ + void resetToDefault() noexcept { targetTree.removeProperty (targetProperty, nullptr); } + + /** You can assign a lambda to this callback and it will called when the default + value is changed. + + @see setDefault + */ + std::function onDefaultChange; + + //============================================================================== + /** Sets the property and returns the new ValueTreePropertyWithDefault. + + This will modify the property in the referenced ValueTree. + */ + ValueTreePropertyWithDefault& operator= (const var& newValue) + { + setValue (newValue, undoManager); + return *this; + } + + /** Sets the property. + + This will modify the property in the referenced ValueTree. + */ + void setValue (const var& newValue, UndoManager* undoManagerToUse) + { + if (auto* array = newValue.getArray()) + targetTree.setProperty (targetProperty, varArrayToDelimitedString (*array), undoManagerToUse); + else + targetTree.setProperty (targetProperty, newValue, undoManagerToUse); + } + + //============================================================================== + /** Makes the ValueTreePropertyWithDefault refer to the specified property inside + the given ValueTree. + + The default value will be an empty var. + */ + void referTo (ValueTree tree, + const Identifier& property, + UndoManager* um) + { + referToWithDefault (tree, property, um, {}, {}); + } + + /** Makes the ValueTreePropertyWithDefault refer to the specified property inside + the given ValueTree. + + The default value will be defaultVal. + */ + void referTo (ValueTree tree, + const Identifier& property, + UndoManager* um, + var defaultVal) + { + referToWithDefault (tree, property, um, Value (defaultVal), {}); + } + + /** Makes the ValueTreePropertyWithDefault refer to the specified property inside + the given ValueTree. + + The default value will be defaultVal. + */ + void referTo (ValueTree tree, + const Identifier& property, + UndoManager* um, + var defaultVal, + StringRef arrayDelimiter) + { + referToWithDefault (tree, property, um, Value (defaultVal), arrayDelimiter); + } + + //============================================================================== + /** Returns a reference to the ValueTree containing the referenced property. */ + ValueTree& getValueTree() noexcept { return targetTree; } + + /** Returns the property ID of the referenced property. */ + Identifier& getPropertyID() noexcept { return targetProperty; } + + /** Returns the UndoManager that is being used. */ + UndoManager* getUndoManager() noexcept { return undoManager; } + + //============================================================================== + ValueTreePropertyWithDefault& operator= (const ValueTreePropertyWithDefault& other) + { + referToWithDefault (other.targetTree, + other.targetProperty, + other.undoManager, + other.defaultValue, + other.delimiter); + + return *this; + } + +private: + //============================================================================== + ValueTree targetTree; + Identifier targetProperty; + UndoManager* undoManager = nullptr; + Value defaultValue; + + String delimiter; + + //============================================================================== + void valueChanged (Value&) override + { + if (onDefaultChange != nullptr) + onDefaultChange(); + } + + //============================================================================== + void referToWithDefault (ValueTree v, + const Identifier& i, + UndoManager* um, + const Value& defaultVal, + StringRef del) + { + targetTree = v; + targetProperty = i; + undoManager = um; + defaultValue.referTo (defaultVal); + delimiter = del; + + defaultValue.addListener (this); + } + + //============================================================================== + String varArrayToDelimitedString (const Array& input) const noexcept + { + // if you are trying to control a var that is an array then you need to + // set a delimiter string that will be used when writing to XML! + jassert (delimiter.isNotEmpty()); + + StringArray elements; + + for (auto& v : input) + elements.add (v.toString()); + + return elements.joinIntoString (delimiter); + } + + Array delimitedStringToVarArray (StringRef input) const noexcept + { + Array arr; + + for (auto t : StringArray::fromTokens (input, delimiter, {})) + arr.add (t); + + return arr; + } +}; + +//============================================================================== +#ifndef DOXYGEN +using ValueWithDefault [[deprecated ("This class has been renamed to better describe what is does. " + "This declaration is here for backwards compatibility and new " + "code should use the new class name.")]] + = ValueTreePropertyWithDefault; +#endif + +} // namespace juce diff --git a/modules/juce_data_structures/values/juce_ValueWithDefault.cpp b/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault_test.cpp similarity index 55% rename from modules/juce_data_structures/values/juce_ValueWithDefault.cpp rename to modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault_test.cpp index 38a7539ca9..08a4c5a101 100644 --- a/modules/juce_data_structures/values/juce_ValueWithDefault.cpp +++ b/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault_test.cpp @@ -26,31 +26,29 @@ namespace juce { -#if JUCE_UNIT_TESTS - -class ValueWithDefaultTests : public UnitTest +class ValueTreePropertyWithDefaultTests : public UnitTest { public: - ValueWithDefaultTests() - : UnitTest ("ValueWithDefault", UnitTestCategories::values) + ValueTreePropertyWithDefaultTests() + : UnitTest ("ValueTreePropertyWithDefault", UnitTestCategories::values) {} void runTest() override { beginTest ("default constructor"); { - ValueWithDefault vwd; - expect (vwd.isUsingDefault()); - expect (vwd.get() == var()); + ValueTreePropertyWithDefault value; + expect (value.isUsingDefault()); + expect (value.get() == var()); } beginTest ("missing property"); { ValueTree t ("root"); - ValueWithDefault vwd (t, "testKey", nullptr, "default"); + ValueTreePropertyWithDefault value (t, "testKey", nullptr, "default"); - expect (vwd.isUsingDefault()); - expectEquals (vwd.get().toString(), String ("default")); + expect (value.isUsingDefault()); + expectEquals (value.get().toString(), String ("default")); } beginTest ("non-empty property"); @@ -58,21 +56,21 @@ public: ValueTree t ("root"); t.setProperty ("testKey", "non-default", nullptr); - ValueWithDefault vwd (t, "testKey", nullptr, "default"); + ValueTreePropertyWithDefault value (t, "testKey", nullptr, "default"); - expect (! vwd.isUsingDefault()); - expectEquals (vwd.get().toString(), String ("non-default")); + expect (! value.isUsingDefault()); + expectEquals (value.get().toString(), String ("non-default")); } beginTest ("set default"); { ValueTree t ("root"); - ValueWithDefault vwd (t, "testkey", nullptr); - vwd.setDefault ("default"); + ValueTreePropertyWithDefault value (t, "testkey", nullptr); + value.setDefault ("default"); - expect (vwd.isUsingDefault()); - expectEquals (vwd.get().toString(), String ("default")); + expect (value.isUsingDefault()); + expectEquals (value.get().toString(), String ("default")); } beginTest ("set value"); @@ -80,22 +78,20 @@ public: ValueTree t ("root"); t.setProperty ("testkey", "testvalue", nullptr); - ValueWithDefault vwd (t, "testkey", nullptr, "default"); - vwd = "newvalue"; + ValueTreePropertyWithDefault value (t, "testkey", nullptr, "default"); + value = "newvalue"; - expect (! vwd.isUsingDefault()); + expect (! value.isUsingDefault()); expectEquals (t["testkey"].toString(), String ("newvalue")); - vwd.resetToDefault(); + value.resetToDefault(); - expect (vwd.isUsingDefault()); + expect (value.isUsingDefault()); expect (t["testkey"] == var()); } } }; -static ValueWithDefaultTests valueWithDefaultTests; - -#endif +static ValueTreePropertyWithDefaultTests valueTreePropertyWithDefaultTests; } // namespace juce diff --git a/modules/juce_data_structures/values/juce_ValueWithDefault.h b/modules/juce_data_structures/values/juce_ValueWithDefault.h deleted file mode 100644 index 8160cdda61..0000000000 --- a/modules/juce_data_structures/values/juce_ValueWithDefault.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2020 - Raw Material Software Limited - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 6 End-User License - Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). - - End User License Agreement: www.juce.com/juce-6-licence - Privacy Policy: www.juce.com/juce-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - This class acts as a wrapper around a property inside a ValueTree. - - If the property inside the ValueTree is missing the ValueWithDefault will automatically - return a default value, which can be specified when initialising the ValueWithDefault. - - @tags{DataStructures} -*/ -class ValueWithDefault -{ -public: - //============================================================================== - /** Creates an unitialised ValueWithDefault. Initialise it using one of the referTo() methods. */ - ValueWithDefault() = default; - - /** Creates an ValueWithDefault object. The default value will be an empty var. */ - ValueWithDefault (ValueTree& tree, const Identifier& propertyID, UndoManager* um) - : targetTree (tree), - targetProperty (propertyID), - undoManager (um), - defaultValue() - { - } - - /** Creates an ValueWithDefault object. The default value will be defaultToUse. */ - ValueWithDefault (ValueTree& tree, const Identifier& propertyID, UndoManager* um, - const var& defaultToUse) - : targetTree (tree), - targetProperty (propertyID), - undoManager (um), - defaultValue (defaultToUse) - { - } - - /** Creates an ValueWithDefault object. The default value will be defaultToUse. - - Use this constructor if the underlying var object being controlled is an array and - it will handle the conversion to/from a delimited String that can be written to - XML format. - */ - ValueWithDefault (ValueTree& tree, const Identifier& propertyID, UndoManager* um, - const var& defaultToUse, StringRef arrayDelimiter) - : targetTree (tree), - targetProperty (propertyID), - undoManager (um), - defaultValue (defaultToUse), - delimiter (arrayDelimiter) - { - } - - /** Creates a ValueWithDefault object from another ValueWithDefault object. */ - ValueWithDefault (const ValueWithDefault& other) - : targetTree (other.targetTree), - targetProperty (other.targetProperty), - undoManager (other.undoManager), - defaultValue (other.defaultValue), - delimiter (other.delimiter) - { - } - - //============================================================================== - /** Returns the current value of the property. If the property does not exist this - returns the default value. - */ - var get() const noexcept - { - if (isUsingDefault()) - return defaultValue; - - if (delimiter.isNotEmpty()) - return delimitedStringToVarArray (targetTree[targetProperty].toString()); - - return targetTree[targetProperty]; - } - - /** Returns the current property as a Value object. */ - Value getPropertyAsValue() { return targetTree.getPropertyAsValue (targetProperty, undoManager); } - - /** Returns the current default value. */ - var getDefault() const { return defaultValue; } - - /** Sets the default value to a new var. */ - void setDefault (const var& newDefault) - { - if (defaultValue != newDefault) - { - defaultValue = newDefault; - - if (onDefaultChange != nullptr) - onDefaultChange(); - } - } - - /** Returns true if the property does not exist in the referenced ValueTree. */ - bool isUsingDefault() const - { - return ! targetTree.hasProperty (targetProperty); - } - - /** Removes the property from the referenced ValueTree. */ - void resetToDefault() noexcept - { - targetTree.removeProperty (targetProperty, nullptr); - } - - /** You can assign a lambda to this callback object to have it called when the default value is changed. */ - std::function onDefaultChange; - - //============================================================================== - /** Sets the property and returns the new ValueWithDefault. This will modify the property in the referenced ValueTree. */ - ValueWithDefault& operator= (const var& newValue) - { - setValue (newValue, undoManager); - return *this; - } - - /** Sets the property. This will actually modify the property in the referenced ValueTree. */ - void setValue (const var& newValue, UndoManager* undoManagerToUse) - { - if (auto* array = newValue.getArray()) - targetTree.setProperty (targetProperty, varArrayToDelimitedString (*array), undoManagerToUse); - else - targetTree.setProperty (targetProperty, newValue, undoManagerToUse); - } - - //============================================================================== - /** Makes the ValueWithDefault refer to the specified property inside the given ValueTree. */ - void referTo (ValueTree& tree, const Identifier& property, UndoManager* um) - { - referToWithDefault (tree, property, um, var(), {}); - } - - /** Makes the ValueWithDefault refer to the specified property inside the given ValueTree, - and specifies a default value to use. - */ - void referTo (ValueTree& tree, const Identifier& property, UndoManager* um, const var& defaultVal) - { - referToWithDefault (tree, property, um, defaultVal, {}); - } - - void referTo (ValueTree& tree, const Identifier& property, UndoManager* um, - const var& defaultVal, StringRef arrayDelimiter) - { - referToWithDefault (tree, property, um, defaultVal, arrayDelimiter); - } - - //============================================================================== - /** Returns a reference to the ValueTree containing the referenced property. */ - ValueTree& getValueTree() noexcept { return targetTree; } - - /** Returns the property ID of the referenced property. */ - Identifier& getPropertyID() noexcept { return targetProperty; } - - /** Returns the UndoManager that is being used. */ - UndoManager* getUndoManager() noexcept { return undoManager; } - - //============================================================================== - ValueWithDefault& operator= (const ValueWithDefault& other) - { - referToWithDefault (other.targetTree, other.targetProperty, other.undoManager, - other.defaultValue, other.delimiter); - - return *this; - } - -private: - //============================================================================== - ValueTree targetTree; - Identifier targetProperty; - UndoManager* undoManager = nullptr; - var defaultValue; - - String delimiter; - - //============================================================================== - void referToWithDefault (const ValueTree& v, const Identifier& i, UndoManager* um, - const var& defaultVal, StringRef del) - { - targetTree = v; - targetProperty = i; - undoManager = um; - defaultValue = defaultVal; - delimiter = del; - } - - //============================================================================== - String varArrayToDelimitedString (const Array& input) const noexcept - { - // if you are trying to control a var that is an array then you need to - // set a delimiter string that will be used when writing to XML! - jassert (delimiter.isNotEmpty()); - - StringArray elements; - - for (auto& v : input) - elements.add (v.toString()); - - return elements.joinIntoString (delimiter); - } - - Array delimitedStringToVarArray (StringRef input) const noexcept - { - Array arr; - - for (auto t : StringArray::fromTokens (input, delimiter, {})) - arr.add (t); - - return arr; - } - - //============================================================================== - JUCE_DECLARE_WEAK_REFERENCEABLE (ValueWithDefault) -}; - -} // namespace juce