upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
		@ -58,10 +58,13 @@ File PropertiesFile::Options::getDefaultFile() const
 | 
			
		||||
    File dir (commonToAllUsers ?  "/Library/"
 | 
			
		||||
                               : "~/Library/");
 | 
			
		||||
 | 
			
		||||
    if (osxLibrarySubFolder != "Preferences" && ! osxLibrarySubFolder.startsWith ("Application Support"))
 | 
			
		||||
    if (osxLibrarySubFolder != "Preferences"
 | 
			
		||||
        && ! osxLibrarySubFolder.startsWith ("Application Support")
 | 
			
		||||
        && ! osxLibrarySubFolder.startsWith ("Containers"))
 | 
			
		||||
    {
 | 
			
		||||
        /* The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
 | 
			
		||||
           have changed their advice, and now stipulate that settings should go in "Library/Application Support".
 | 
			
		||||
           have changed their advice, and now stipulate that settings should go in "Library/Application Support",
 | 
			
		||||
           or Library/Containers/[app_bundle_id] for a sandboxed app.
 | 
			
		||||
 | 
			
		||||
           Because older apps would be broken by a silent change in this class's behaviour, you must now
 | 
			
		||||
           explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
 | 
			
		||||
 | 
			
		||||
@ -180,7 +180,7 @@ public:
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        When deleted, the file will first call saveIfNeeded() to flush any changes to disk.
 | 
			
		||||
    */
 | 
			
		||||
    ~PropertiesFile();
 | 
			
		||||
    ~PropertiesFile() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if this file was created from a valid (or non-existent) file.
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,7 @@
 | 
			
		||||
#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"
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@
 | 
			
		||||
 | 
			
		||||
  ID:               juce_data_structures
 | 
			
		||||
  vendor:           juce
 | 
			
		||||
  version:          5.3.2
 | 
			
		||||
  version:          5.4.3
 | 
			
		||||
  name:             JUCE data model helper classes
 | 
			
		||||
  description:      Classes for undo/redo management, and smart data structures.
 | 
			
		||||
  website:          http://www.juce.com/juce
 | 
			
		||||
 | 
			
		||||
@ -29,9 +29,7 @@ namespace juce
 | 
			
		||||
 | 
			
		||||
struct UndoManager::ActionSet
 | 
			
		||||
{
 | 
			
		||||
    ActionSet (const String& transactionName)
 | 
			
		||||
        : name (transactionName),
 | 
			
		||||
          time (Time::getCurrentTime())
 | 
			
		||||
    ActionSet (const String& transactionName)  : name (transactionName)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    bool perform() const
 | 
			
		||||
@ -64,7 +62,7 @@ struct UndoManager::ActionSet
 | 
			
		||||
 | 
			
		||||
    OwnedArray<UndoableAction> actions;
 | 
			
		||||
    String name;
 | 
			
		||||
    Time time;
 | 
			
		||||
    Time time { Time::getCurrentTime() };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
@ -117,9 +115,9 @@ bool UndoManager::perform (UndoableAction* newAction)
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_ptr<UndoableAction> action (newAction);
 | 
			
		||||
 | 
			
		||||
        if (reentrancyCheck)
 | 
			
		||||
        if (isPerformingUndoRedo())
 | 
			
		||||
        {
 | 
			
		||||
            jassertfalse;  // don't call perform() recursively from the UndoableAction::perform()
 | 
			
		||||
            jassertfalse;  // Don't call perform() recursively from the UndoableAction::perform()
 | 
			
		||||
                           // or undo() methods, or else these actions will be discarded!
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@ -209,18 +207,18 @@ void UndoManager::dropOldTransactionsIfTooLarge()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UndoManager::beginNewTransaction() noexcept
 | 
			
		||||
void UndoManager::beginNewTransaction()
 | 
			
		||||
{
 | 
			
		||||
    beginNewTransaction ({});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UndoManager::beginNewTransaction (const String& actionName) noexcept
 | 
			
		||||
void UndoManager::beginNewTransaction (const String& actionName)
 | 
			
		||||
{
 | 
			
		||||
    newTransaction = true;
 | 
			
		||||
    newTransactionName = actionName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UndoManager::setCurrentTransactionName (const String& newName) noexcept
 | 
			
		||||
void UndoManager::setCurrentTransactionName (const String& newName)
 | 
			
		||||
{
 | 
			
		||||
    if (newTransaction)
 | 
			
		||||
        newTransactionName = newName;
 | 
			
		||||
@ -228,7 +226,7 @@ void UndoManager::setCurrentTransactionName (const String& newName) noexcept
 | 
			
		||||
        action->name = newName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String UndoManager::getCurrentTransactionName() const noexcept
 | 
			
		||||
String UndoManager::getCurrentTransactionName() const
 | 
			
		||||
{
 | 
			
		||||
    if (auto* action = getCurrentSet())
 | 
			
		||||
        return action->name;
 | 
			
		||||
@ -237,17 +235,19 @@ String UndoManager::getCurrentTransactionName() const noexcept
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
UndoManager::ActionSet* UndoManager::getCurrentSet() const noexcept     { return transactions[nextIndex - 1]; }
 | 
			
		||||
UndoManager::ActionSet* UndoManager::getNextSet() const noexcept        { return transactions[nextIndex]; }
 | 
			
		||||
UndoManager::ActionSet* UndoManager::getCurrentSet() const     { return transactions[nextIndex - 1]; }
 | 
			
		||||
UndoManager::ActionSet* UndoManager::getNextSet() const        { return transactions[nextIndex]; }
 | 
			
		||||
 | 
			
		||||
bool UndoManager::canUndo() const noexcept   { return getCurrentSet() != nullptr; }
 | 
			
		||||
bool UndoManager::canRedo() const noexcept   { return getNextSet()    != nullptr; }
 | 
			
		||||
bool UndoManager::isPerformingUndoRedo() const  { return isInsideUndoRedoCall; }
 | 
			
		||||
 | 
			
		||||
bool UndoManager::canUndo() const      { return getCurrentSet() != nullptr; }
 | 
			
		||||
bool UndoManager::canRedo() const      { return getNextSet()    != nullptr; }
 | 
			
		||||
 | 
			
		||||
bool UndoManager::undo()
 | 
			
		||||
{
 | 
			
		||||
    if (auto* s = getCurrentSet())
 | 
			
		||||
    {
 | 
			
		||||
        const ScopedValueSetter<bool> setter (reentrancyCheck, true);
 | 
			
		||||
        const ScopedValueSetter<bool> setter (isInsideUndoRedoCall, true);
 | 
			
		||||
 | 
			
		||||
        if (s->undo())
 | 
			
		||||
            --nextIndex;
 | 
			
		||||
@ -266,7 +266,7 @@ bool UndoManager::redo()
 | 
			
		||||
{
 | 
			
		||||
    if (auto* s = getNextSet())
 | 
			
		||||
    {
 | 
			
		||||
        const ScopedValueSetter<bool> setter (reentrancyCheck, true);
 | 
			
		||||
        const ScopedValueSetter<bool> setter (isInsideUndoRedoCall, true);
 | 
			
		||||
 | 
			
		||||
        if (s->perform())
 | 
			
		||||
            ++nextIndex;
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ public:
 | 
			
		||||
                 int minimumTransactionsToKeep = 30);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~UndoManager();
 | 
			
		||||
    ~UndoManager() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Deletes all stored actions in the list. */
 | 
			
		||||
@ -126,7 +126,7 @@ public:
 | 
			
		||||
        method are grouped together and undone/redone together by a single call to
 | 
			
		||||
        undo() or redo().
 | 
			
		||||
    */
 | 
			
		||||
    void beginNewTransaction() noexcept;
 | 
			
		||||
    void beginNewTransaction();
 | 
			
		||||
 | 
			
		||||
    /** Starts a new group of actions that together will be treated as a single transaction.
 | 
			
		||||
 | 
			
		||||
@ -137,7 +137,7 @@ public:
 | 
			
		||||
        @param actionName   a description of the transaction that is about to be
 | 
			
		||||
                            performed
 | 
			
		||||
    */
 | 
			
		||||
    void beginNewTransaction (const String& actionName) noexcept;
 | 
			
		||||
    void beginNewTransaction (const String& actionName);
 | 
			
		||||
 | 
			
		||||
    /** Changes the name stored for the current transaction.
 | 
			
		||||
 | 
			
		||||
@ -145,18 +145,18 @@ public:
 | 
			
		||||
        called, but this can be used to change that name without starting a new
 | 
			
		||||
        transaction.
 | 
			
		||||
    */
 | 
			
		||||
    void setCurrentTransactionName (const String& newName) noexcept;
 | 
			
		||||
    void setCurrentTransactionName (const String& newName);
 | 
			
		||||
 | 
			
		||||
    /** Returns the name of the current transaction.
 | 
			
		||||
        @see setCurrentTransactionName
 | 
			
		||||
    */
 | 
			
		||||
    String getCurrentTransactionName() const noexcept;
 | 
			
		||||
    String getCurrentTransactionName() const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if there's at least one action in the list to undo.
 | 
			
		||||
        @see getUndoDescription, undo, canRedo
 | 
			
		||||
    */
 | 
			
		||||
    bool canUndo() const noexcept;
 | 
			
		||||
    bool canUndo() const;
 | 
			
		||||
 | 
			
		||||
    /** Tries to roll-back the last transaction.
 | 
			
		||||
        @returns    true if the transaction can be undone, and false if it fails, or
 | 
			
		||||
@ -217,7 +217,7 @@ public:
 | 
			
		||||
    /** Returns true if there's at least one action in the list to redo.
 | 
			
		||||
        @see getRedoDescription, redo, canUndo
 | 
			
		||||
    */
 | 
			
		||||
    bool canRedo() const noexcept;
 | 
			
		||||
    bool canRedo() const;
 | 
			
		||||
 | 
			
		||||
    /** Tries to redo the last transaction that was undone.
 | 
			
		||||
        @returns   true if the transaction can be redone, and false if it fails, or
 | 
			
		||||
@ -243,16 +243,18 @@ public:
 | 
			
		||||
    */
 | 
			
		||||
    Time getTimeOfRedoTransaction() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the caller code is in the middle of an undo or redo action. */
 | 
			
		||||
    bool isPerformingUndoRedo() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct ActionSet;
 | 
			
		||||
    friend struct ContainerDeletePolicy<ActionSet>;
 | 
			
		||||
    OwnedArray<ActionSet> transactions, stashedFutureTransactions;
 | 
			
		||||
    String newTransactionName;
 | 
			
		||||
    int totalUnitsStored = 0, maxNumUnitsToKeep = 0, minimumTransactionsToKeep = 0, nextIndex = 0;
 | 
			
		||||
    bool newTransaction = true, reentrancyCheck = false;
 | 
			
		||||
    ActionSet* getCurrentSet() const noexcept;
 | 
			
		||||
    ActionSet* getNextSet() const noexcept;
 | 
			
		||||
    bool newTransaction = true, isInsideUndoRedoCall = false;
 | 
			
		||||
    ActionSet* getCurrentSet() const;
 | 
			
		||||
    ActionSet* getNextSet() const;
 | 
			
		||||
    void moveFutureTransactionsToStash();
 | 
			
		||||
    void restoreStashedFutureTransactions();
 | 
			
		||||
    void dropOldTransactionsIfTooLarge();
 | 
			
		||||
 | 
			
		||||
@ -40,11 +40,11 @@ class JUCE_API  UndoableAction
 | 
			
		||||
{
 | 
			
		||||
protected:
 | 
			
		||||
    /** Creates an action. */
 | 
			
		||||
    UndoableAction() noexcept   {}
 | 
			
		||||
    UndoableAction() = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    virtual ~UndoableAction()   {}
 | 
			
		||||
    virtual ~UndoableAction() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Overridden by a subclass to perform the action.
 | 
			
		||||
 | 
			
		||||
@ -144,11 +144,6 @@ public:
 | 
			
		||||
 | 
			
		||||
            expect (t["testkey"] == var());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("reset value");
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -181,11 +181,14 @@ public:
 | 
			
		||||
    /** Returns the property ID of the referenced property. */
 | 
			
		||||
    const Identifier& getPropertyID() const noexcept        { return targetProperty; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the UndoManager that is being used. */
 | 
			
		||||
    UndoManager* getUndoManager() noexcept                  { return undoManager; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ValueTree targetTree;
 | 
			
		||||
    Identifier targetProperty;
 | 
			
		||||
    UndoManager* undoManager;
 | 
			
		||||
    UndoManager* undoManager = nullptr;
 | 
			
		||||
    Type defaultValue;
 | 
			
		||||
    Type cachedValue;
 | 
			
		||||
 | 
			
		||||
@ -199,13 +202,15 @@ private:
 | 
			
		||||
    void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
 | 
			
		||||
    void valueTreeParentChanged (ValueTree&) override {}
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_WEAK_REFERENCEABLE (CachedValue)
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (CachedValue)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
template <typename Type>
 | 
			
		||||
inline CachedValue<Type>::CachedValue()  : undoManager (nullptr) {}
 | 
			
		||||
inline CachedValue<Type>::CachedValue() = default;
 | 
			
		||||
 | 
			
		||||
template <typename Type>
 | 
			
		||||
inline CachedValue<Type>::CachedValue (ValueTree& v, const Identifier& i, UndoManager* um)
 | 
			
		||||
 | 
			
		||||
@ -123,7 +123,7 @@ Value::Value (Value&& other) noexcept
 | 
			
		||||
    jassert (other.listeners.size() == 0);
 | 
			
		||||
 | 
			
		||||
    other.removeFromListenerList();
 | 
			
		||||
    value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value);
 | 
			
		||||
    value = std::move (other.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Value& Value::operator= (Value&& other) noexcept
 | 
			
		||||
@ -133,7 +133,7 @@ Value& Value::operator= (Value&& other) noexcept
 | 
			
		||||
    jassert (other.listeners.size() == 0);
 | 
			
		||||
 | 
			
		||||
    other.removeFromListenerList();
 | 
			
		||||
    value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value);
 | 
			
		||||
    value = std::move (other.value);
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -138,8 +138,8 @@ public:
 | 
			
		||||
    class JUCE_API  Listener
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        Listener()          {}
 | 
			
		||||
        virtual ~Listener() {}
 | 
			
		||||
        Listener() = default;
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        /** Called when a Value object is changed.
 | 
			
		||||
 | 
			
		||||
@ -180,7 +180,7 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ValueSource();
 | 
			
		||||
        virtual ~ValueSource();
 | 
			
		||||
        ~ValueSource() override;
 | 
			
		||||
 | 
			
		||||
        /** Returns the current value of this object. */
 | 
			
		||||
        virtual var getValue() const = 0;
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        for (auto* c : other.children)
 | 
			
		||||
        {
 | 
			
		||||
            auto child = new SharedObject (*c);
 | 
			
		||||
            auto* child = new SharedObject (*c);
 | 
			
		||||
            child->parent = this;
 | 
			
		||||
            children.add (child);
 | 
			
		||||
        }
 | 
			
		||||
@ -51,18 +51,18 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        jassert (parent == nullptr); // this should never happen unless something isn't obeying the ref-counting!
 | 
			
		||||
 | 
			
		||||
        for (int i = children.size(); --i >= 0;)
 | 
			
		||||
        for (auto i = children.size(); --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            const Ptr c (children.getObjectPointerUnchecked(i));
 | 
			
		||||
            const Ptr c (children.getObjectPointerUnchecked (i));
 | 
			
		||||
            c->parent = nullptr;
 | 
			
		||||
            children.remove (i);
 | 
			
		||||
            c->sendParentChangeMessage();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SharedObject* getRoot() noexcept
 | 
			
		||||
    SharedObject& getRoot() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return parent == nullptr ? this : parent->getRoot();
 | 
			
		||||
        return parent == nullptr ? *this : parent->getRoot();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Function>
 | 
			
		||||
@ -72,7 +72,7 @@ public:
 | 
			
		||||
 | 
			
		||||
        if (numListeners == 1)
 | 
			
		||||
        {
 | 
			
		||||
            valueTreesWithListeners.getUnchecked(0)->listeners.callExcluding (listenerToExclude, fn);
 | 
			
		||||
            valueTreesWithListeners.getUnchecked (0)->listeners.callExcluding (listenerToExclude, fn);
 | 
			
		||||
        }
 | 
			
		||||
        else if (numListeners > 0)
 | 
			
		||||
        {
 | 
			
		||||
@ -80,7 +80,7 @@ public:
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < numListeners; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                auto* v = listenersCopy.getUnchecked(i);
 | 
			
		||||
                auto* v = listenersCopy.getUnchecked (i);
 | 
			
		||||
 | 
			
		||||
                if (i == 0 || valueTreesWithListeners.contains (v))
 | 
			
		||||
                    v->listeners.callExcluding (listenerToExclude, fn);
 | 
			
		||||
@ -97,33 +97,33 @@ public:
 | 
			
		||||
 | 
			
		||||
    void sendPropertyChangeMessage (const Identifier& property, ValueTree::Listener* listenerToExclude = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        ValueTree tree (this);
 | 
			
		||||
        ValueTree tree (*this);
 | 
			
		||||
        callListenersForAllParents (listenerToExclude, [&] (Listener& l) { l.valueTreePropertyChanged (tree, property); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void sendChildAddedMessage (ValueTree child)
 | 
			
		||||
    {
 | 
			
		||||
        ValueTree tree (this);
 | 
			
		||||
        ValueTree tree (*this);
 | 
			
		||||
        callListenersForAllParents (nullptr, [&] (Listener& l) { l.valueTreeChildAdded (tree, child); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void sendChildRemovedMessage (ValueTree child, int index)
 | 
			
		||||
    {
 | 
			
		||||
        ValueTree tree (this);
 | 
			
		||||
        ValueTree tree (*this);
 | 
			
		||||
        callListenersForAllParents (nullptr, [=, &tree, &child] (Listener& l) { l.valueTreeChildRemoved (tree, child, index); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void sendChildOrderChangedMessage (int oldIndex, int newIndex)
 | 
			
		||||
    {
 | 
			
		||||
        ValueTree tree (this);
 | 
			
		||||
        ValueTree tree (*this);
 | 
			
		||||
        callListenersForAllParents (nullptr, [=, &tree] (Listener& l) { l.valueTreeChildOrderChanged (tree, oldIndex, newIndex); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void sendParentChangeMessage()
 | 
			
		||||
    {
 | 
			
		||||
        ValueTree tree (this);
 | 
			
		||||
        ValueTree tree (*this);
 | 
			
		||||
 | 
			
		||||
        for (int j = children.size(); --j >= 0;)
 | 
			
		||||
        for (auto j = children.size(); --j >= 0;)
 | 
			
		||||
            if (auto* child = children.getObjectPointer (j))
 | 
			
		||||
                child->sendParentChangeMessage();
 | 
			
		||||
 | 
			
		||||
@ -143,12 +143,12 @@ public:
 | 
			
		||||
            if (auto* existingValue = properties.getVarPointer (name))
 | 
			
		||||
            {
 | 
			
		||||
                if (*existingValue != newValue)
 | 
			
		||||
                    undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue,
 | 
			
		||||
                    undoManager->perform (new SetPropertyAction (*this, name, newValue, *existingValue,
 | 
			
		||||
                                                                 false, false, listenerToExclude));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                undoManager->perform (new SetPropertyAction (this, name, newValue, {},
 | 
			
		||||
                undoManager->perform (new SetPropertyAction (*this, name, newValue, {},
 | 
			
		||||
                                                             true, false, listenerToExclude));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -169,7 +169,7 @@ public:
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (properties.contains (name))
 | 
			
		||||
                undoManager->perform (new SetPropertyAction (this, name, {}, properties [name], false, true));
 | 
			
		||||
                undoManager->perform (new SetPropertyAction (*this, name, {}, properties[name], false, true));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -186,27 +186,27 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = properties.size(); --i >= 0;)
 | 
			
		||||
                undoManager->perform (new SetPropertyAction (this, properties.getName(i), {},
 | 
			
		||||
                                                             properties.getValueAt(i), false, true));
 | 
			
		||||
            for (auto i = properties.size(); --i >= 0;)
 | 
			
		||||
                undoManager->perform (new SetPropertyAction (*this, properties.getName (i), {},
 | 
			
		||||
                                                             properties.getValueAt (i), false, true));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void copyPropertiesFrom (const SharedObject& source, UndoManager* undoManager)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = properties.size(); --i >= 0;)
 | 
			
		||||
        for (auto i = properties.size(); --i >= 0;)
 | 
			
		||||
            if (! source.properties.contains (properties.getName (i)))
 | 
			
		||||
                removeProperty (properties.getName (i), undoManager);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < source.properties.size(); ++i)
 | 
			
		||||
            setProperty (source.properties.getName(i), source.properties.getValueAt(i), undoManager);
 | 
			
		||||
            setProperty (source.properties.getName (i), source.properties.getValueAt (i), undoManager);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ValueTree getChildWithName (const Identifier& typeToMatch) const
 | 
			
		||||
    {
 | 
			
		||||
        for (auto* s : children)
 | 
			
		||||
            if (s->type == typeToMatch)
 | 
			
		||||
                return ValueTree (s);
 | 
			
		||||
                return ValueTree (*s);
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
@ -215,18 +215,18 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        for (auto* s : children)
 | 
			
		||||
            if (s->type == typeToMatch)
 | 
			
		||||
                return ValueTree (s);
 | 
			
		||||
                return ValueTree (*s);
 | 
			
		||||
 | 
			
		||||
        auto newObject = new SharedObject (typeToMatch);
 | 
			
		||||
        addChild (newObject, -1, undoManager);
 | 
			
		||||
        return ValueTree (newObject);
 | 
			
		||||
        return ValueTree (*newObject);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
 | 
			
		||||
    {
 | 
			
		||||
        for (auto* s : children)
 | 
			
		||||
            if (s->properties[propertyName] == propertyValue)
 | 
			
		||||
                return ValueTree (s);
 | 
			
		||||
                return ValueTree (*s);
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
@ -266,7 +266,7 @@ public:
 | 
			
		||||
                {
 | 
			
		||||
                    children.insert (index, child);
 | 
			
		||||
                    child->parent = this;
 | 
			
		||||
                    sendChildAddedMessage (ValueTree (child));
 | 
			
		||||
                    sendChildAddedMessage (ValueTree (*child));
 | 
			
		||||
                    child->sendParentChangeMessage();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
@ -274,7 +274,7 @@ public:
 | 
			
		||||
                    if (! isPositiveAndBelow (index, children.size()))
 | 
			
		||||
                        index = children.size();
 | 
			
		||||
 | 
			
		||||
                    undoManager->perform (new AddOrRemoveChildAction (this, index, child));
 | 
			
		||||
                    undoManager->perform (new AddOrRemoveChildAction (*this, index, child));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
@ -288,7 +288,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    void removeChild (int childIndex, UndoManager* undoManager)
 | 
			
		||||
    {
 | 
			
		||||
        if (Ptr child = children.getObjectPointer (childIndex))
 | 
			
		||||
        if (auto child = Ptr (children.getObjectPointer (childIndex)))
 | 
			
		||||
        {
 | 
			
		||||
            if (undoManager == nullptr)
 | 
			
		||||
            {
 | 
			
		||||
@ -299,7 +299,7 @@ public:
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                undoManager->perform (new AddOrRemoveChildAction (this, childIndex, nullptr));
 | 
			
		||||
                undoManager->perform (new AddOrRemoveChildAction (*this, childIndex, {}));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -328,7 +328,7 @@ public:
 | 
			
		||||
                if (! isPositiveAndBelow (newIndex, children.size()))
 | 
			
		||||
                    newIndex = children.size() - 1;
 | 
			
		||||
 | 
			
		||||
                undoManager->perform (new MoveChildAction (this, currentIndex, newIndex));
 | 
			
		||||
                undoManager->perform (new MoveChildAction (*this, currentIndex, newIndex));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -339,7 +339,7 @@ public:
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < children.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto* child = newOrder.getUnchecked(i)->object.get();
 | 
			
		||||
            auto* child = newOrder.getUnchecked (i)->object.get();
 | 
			
		||||
 | 
			
		||||
            if (children.getObjectPointerUnchecked (i) != child)
 | 
			
		||||
            {
 | 
			
		||||
@ -359,7 +359,7 @@ public:
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < children.size(); ++i)
 | 
			
		||||
            if (! children.getObjectPointerUnchecked(i)->isEquivalentTo (*other.children.getObjectPointerUnchecked(i)))
 | 
			
		||||
            if (! children.getObjectPointerUnchecked (i)->isEquivalentTo (*other.children.getObjectPointerUnchecked (i)))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
@ -367,12 +367,12 @@ public:
 | 
			
		||||
 | 
			
		||||
    XmlElement* createXml() const
 | 
			
		||||
    {
 | 
			
		||||
        auto xml = new XmlElement (type);
 | 
			
		||||
        auto* xml = new XmlElement (type);
 | 
			
		||||
        properties.copyToXmlAttributes (*xml);
 | 
			
		||||
 | 
			
		||||
        // (NB: it's faster to add nodes to XML elements in reverse order)
 | 
			
		||||
        for (int i = children.size(); --i >= 0;)
 | 
			
		||||
            xml->prependChildElement (children.getObjectPointerUnchecked(i)->createXml());
 | 
			
		||||
        for (auto i = children.size(); --i >= 0;)
 | 
			
		||||
            xml->prependChildElement (children.getObjectPointerUnchecked (i)->createXml());
 | 
			
		||||
 | 
			
		||||
        return xml;
 | 
			
		||||
    }
 | 
			
		||||
@ -385,13 +385,13 @@ public:
 | 
			
		||||
        for (int j = 0; j < properties.size(); ++j)
 | 
			
		||||
        {
 | 
			
		||||
            output.writeString (properties.getName (j).toString());
 | 
			
		||||
            properties.getValueAt(j).writeToStream (output);
 | 
			
		||||
            properties.getValueAt (j).writeToStream (output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        output.writeCompressedInt (children.size());
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < children.size(); ++i)
 | 
			
		||||
            writeObjectToStream (output, children.getObjectPointerUnchecked(i));
 | 
			
		||||
        for (auto* c : children)
 | 
			
		||||
            writeObjectToStream (output, c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void writeObjectToStream (OutputStream& output, const SharedObject* object)
 | 
			
		||||
@ -411,10 +411,11 @@ public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct SetPropertyAction  : public UndoableAction
 | 
			
		||||
    {
 | 
			
		||||
        SetPropertyAction (SharedObject* so, const Identifier& propertyName,
 | 
			
		||||
        SetPropertyAction (Ptr targetObject, const Identifier& propertyName,
 | 
			
		||||
                           const var& newVal, const var& oldVal, bool isAdding, bool isDeleting,
 | 
			
		||||
                           ValueTree::Listener* listenerToExclude = nullptr)
 | 
			
		||||
            : target (so), name (propertyName), newValue (newVal), oldValue (oldVal),
 | 
			
		||||
            : target (std::move (targetObject)),
 | 
			
		||||
              name (propertyName), newValue (newVal), oldValue (oldVal),
 | 
			
		||||
              isAddingNewProperty (isAdding), isDeletingProperty (isDeleting),
 | 
			
		||||
              excludeListener (listenerToExclude)
 | 
			
		||||
        {
 | 
			
		||||
@ -454,7 +455,7 @@ public:
 | 
			
		||||
                if (auto* next = dynamic_cast<SetPropertyAction*> (nextAction))
 | 
			
		||||
                    if (next->target == target && next->name == name
 | 
			
		||||
                          && ! (next->isAddingNewProperty || next->isDeletingProperty))
 | 
			
		||||
                        return new SetPropertyAction (target, name, next->newValue, oldValue, false, false);
 | 
			
		||||
                        return new SetPropertyAction (*target, name, next->newValue, oldValue, false, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return nullptr;
 | 
			
		||||
@ -474,9 +475,9 @@ public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct AddOrRemoveChildAction  : public UndoableAction
 | 
			
		||||
    {
 | 
			
		||||
        AddOrRemoveChildAction (SharedObject* parentObject, int index, SharedObject* newChild)
 | 
			
		||||
            : target (parentObject),
 | 
			
		||||
              child (newChild != nullptr ? newChild : parentObject->children.getObjectPointer (index)),
 | 
			
		||||
        AddOrRemoveChildAction (Ptr parentObject, int index, SharedObject* newChild)
 | 
			
		||||
            : target (std::move (parentObject)),
 | 
			
		||||
              child (newChild != nullptr ? newChild : target->children.getObjectPointer (index)),
 | 
			
		||||
              childIndex (index),
 | 
			
		||||
              isDeleting (newChild == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
@ -488,7 +489,7 @@ public:
 | 
			
		||||
            if (isDeleting)
 | 
			
		||||
                target->removeChild (childIndex, nullptr);
 | 
			
		||||
            else
 | 
			
		||||
                target->addChild (child, childIndex, nullptr);
 | 
			
		||||
                target->addChild (child.get(), childIndex, nullptr);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
@ -497,7 +498,7 @@ public:
 | 
			
		||||
        {
 | 
			
		||||
            if (isDeleting)
 | 
			
		||||
            {
 | 
			
		||||
                target->addChild (child, childIndex, nullptr);
 | 
			
		||||
                target->addChild (child.get(), childIndex, nullptr);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
@ -526,8 +527,8 @@ public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct MoveChildAction  : public UndoableAction
 | 
			
		||||
    {
 | 
			
		||||
        MoveChildAction (SharedObject* parentObject, int fromIndex, int toIndex) noexcept
 | 
			
		||||
            : parent (parentObject), startIndex (fromIndex), endIndex (toIndex)
 | 
			
		||||
        MoveChildAction (Ptr parentObject, int fromIndex, int toIndex) noexcept
 | 
			
		||||
            : parent (std::move (parentObject)), startIndex (fromIndex), endIndex (toIndex)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -587,20 +588,18 @@ ValueTree::ValueTree (const Identifier& type)  : object (new ValueTree::SharedOb
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree::ValueTree (const Identifier& type,
 | 
			
		||||
                      std::initializer_list<std::pair<Identifier, var>> properties,
 | 
			
		||||
                      std::initializer_list<NamedValueSet::NamedValue> properties,
 | 
			
		||||
                      std::initializer_list<ValueTree> subTrees)
 | 
			
		||||
    : ValueTree (type)
 | 
			
		||||
{
 | 
			
		||||
    for (auto& prop : properties)
 | 
			
		||||
        setProperty (prop.first, prop.second, nullptr);
 | 
			
		||||
    object->properties = NamedValueSet (std::move (properties));
 | 
			
		||||
 | 
			
		||||
    for (auto& tree : subTrees)
 | 
			
		||||
        addChild (tree, -1, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree::ValueTree (SharedObject* so) noexcept  : object (so)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
ValueTree::ValueTree (SharedObject::Ptr so) noexcept  : object (std::move (so)) {}
 | 
			
		||||
ValueTree::ValueTree (SharedObject& so) noexcept      : object (so) {}
 | 
			
		||||
 | 
			
		||||
ValueTree::ValueTree (const ValueTree& other) noexcept  : object (other.object)
 | 
			
		||||
{
 | 
			
		||||
@ -632,7 +631,7 @@ ValueTree& ValueTree::operator= (const ValueTree& other)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree::ValueTree (ValueTree&& other) noexcept
 | 
			
		||||
    : object (static_cast<SharedObject::Ptr&&> (other.object))
 | 
			
		||||
    : object (std::move (other.object))
 | 
			
		||||
{
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        object->valueTreesWithListeners.removeValue (&other);
 | 
			
		||||
@ -663,7 +662,32 @@ bool ValueTree::isEquivalentTo (const ValueTree& other) const
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::createCopy() const
 | 
			
		||||
{
 | 
			
		||||
    return ValueTree (createCopyIfNotNull (object.get()));
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        return ValueTree (*new SharedObject (*object));
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueTree::copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager)
 | 
			
		||||
{
 | 
			
		||||
    jassert (object != nullptr || source.object == nullptr); // Trying to add properties to a null ValueTree will fail!
 | 
			
		||||
 | 
			
		||||
    if (source.object == nullptr)
 | 
			
		||||
        removeAllProperties (undoManager);
 | 
			
		||||
    else if (object != nullptr)
 | 
			
		||||
        object->copyPropertiesFrom (*(source.object), undoManager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueTree::copyPropertiesAndChildrenFrom (const ValueTree& source, UndoManager* undoManager)
 | 
			
		||||
{
 | 
			
		||||
    jassert (object != nullptr || source.object == nullptr); // Trying to copy to a null ValueTree will fail!
 | 
			
		||||
 | 
			
		||||
    copyPropertiesFrom (source, undoManager);
 | 
			
		||||
    removeAllChildren (undoManager);
 | 
			
		||||
 | 
			
		||||
    if (object != nullptr && source.object != nullptr)
 | 
			
		||||
        for (auto& child : source.object->children)
 | 
			
		||||
            object->addChild (createCopyIfNotNull (child), -1, undoManager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ValueTree::hasType (const Identifier& typeName) const noexcept
 | 
			
		||||
@ -678,23 +702,29 @@ Identifier ValueTree::getType() const noexcept
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::getParent() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return ValueTree (object != nullptr ? object->parent
 | 
			
		||||
                                        : static_cast<SharedObject*> (nullptr));
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        if (auto p = object->parent)
 | 
			
		||||
            return ValueTree (*p);
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::getRoot() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return ValueTree (object != nullptr ? object->getRoot()
 | 
			
		||||
                                        : static_cast<SharedObject*> (nullptr));
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        return ValueTree (object->getRoot());
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::getSibling (int delta) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    if (object == nullptr || object->parent == nullptr)
 | 
			
		||||
        return {};
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        if (auto* p = object->parent)
 | 
			
		||||
            if (auto* c = p->children.getObjectPointer (p->indexOf (*this) + delta))
 | 
			
		||||
                return ValueTree (*c);
 | 
			
		||||
 | 
			
		||||
    auto index = object->parent->indexOf (*this) + delta;
 | 
			
		||||
    return ValueTree (object->parent->children.getObjectPointer (index));
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const var& getNullVarRef() noexcept
 | 
			
		||||
@ -770,16 +800,6 @@ Identifier ValueTree::getPropertyName (int index) const noexcept
 | 
			
		||||
                             : object->properties.getName (index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueTree::copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager)
 | 
			
		||||
{
 | 
			
		||||
    jassert (object != nullptr || source.object == nullptr); // Trying to add properties to a null ValueTree will fail!
 | 
			
		||||
 | 
			
		||||
    if (source.object == nullptr)
 | 
			
		||||
        removeAllProperties (undoManager);
 | 
			
		||||
    else if (object != nullptr)
 | 
			
		||||
        object->copyPropertiesFrom (*(source.object), undoManager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ValueTree::getReferenceCount() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return object != nullptr ? object->getReferenceCount() : 0;
 | 
			
		||||
@ -795,12 +815,12 @@ struct ValueTreePropertyValueSource  : public Value::ValueSource,
 | 
			
		||||
        tree.addListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ValueTreePropertyValueSource()
 | 
			
		||||
    ~ValueTreePropertyValueSource() override
 | 
			
		||||
    {
 | 
			
		||||
        tree.removeListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var getValue() const override                 { return tree [property]; }
 | 
			
		||||
    var getValue() const override                 { return tree[property]; }
 | 
			
		||||
    void setValue (const var& newValue) override  { tree.setProperty (property, newValue, undoManager); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@ -836,29 +856,30 @@ int ValueTree::getNumChildren() const noexcept
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::getChild (int index) const
 | 
			
		||||
{
 | 
			
		||||
    return ValueTree (object != nullptr ? object->children.getObjectPointer (index)
 | 
			
		||||
                                        : static_cast<SharedObject*> (nullptr));
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        if (auto* c = object->children.getObjectPointer (index))
 | 
			
		||||
            return ValueTree (*c);
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree::Iterator::Iterator (const ValueTree& v, bool isEnd) noexcept
 | 
			
		||||
ValueTree::Iterator::Iterator (const ValueTree& v, bool isEnd)
 | 
			
		||||
   : internal (v.object != nullptr ? (isEnd ? v.object->children.end() : v.object->children.begin()) : nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree::Iterator& ValueTree::Iterator::operator++() noexcept
 | 
			
		||||
ValueTree::Iterator& ValueTree::Iterator::operator++()
 | 
			
		||||
{
 | 
			
		||||
    internal = static_cast<SharedObject**> (internal) + 1;
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ValueTree::Iterator::operator!= (const Iterator& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return internal != other.internal;
 | 
			
		||||
}
 | 
			
		||||
bool ValueTree::Iterator::operator== (const Iterator& other) const  { return internal == other.internal; }
 | 
			
		||||
bool ValueTree::Iterator::operator!= (const Iterator& other) const  { return internal != other.internal; }
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::Iterator::operator*() const
 | 
			
		||||
{
 | 
			
		||||
    return ValueTree (*static_cast<SharedObject**> (internal));
 | 
			
		||||
    return ValueTree (SharedObject::Ptr (*static_cast<SharedObject**> (internal)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree::Iterator ValueTree::begin() const noexcept   { return Iterator (*this, false); }
 | 
			
		||||
@ -881,7 +902,7 @@ ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const
 | 
			
		||||
 | 
			
		||||
bool ValueTree::isAChildOf (const ValueTree& possibleParent) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return object != nullptr && object->isAChildOf (possibleParent.object);
 | 
			
		||||
    return object != nullptr && object->isAChildOf (possibleParent.object.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ValueTree::indexOf (const ValueTree& child) const noexcept
 | 
			
		||||
@ -894,7 +915,7 @@ void ValueTree::addChild (const ValueTree& child, int index, UndoManager* undoMa
 | 
			
		||||
    jassert (object != nullptr); // Trying to add a child to a null ValueTree!
 | 
			
		||||
 | 
			
		||||
    if (object != nullptr)
 | 
			
		||||
        object->addChild (child.object, index, undoManager);
 | 
			
		||||
        object->addChild (child.object.get(), index, undoManager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueTree::appendChild (const ValueTree& child, UndoManager* undoManager)
 | 
			
		||||
@ -932,7 +953,10 @@ void ValueTree::createListOfChildren (OwnedArray<ValueTree>& list) const
 | 
			
		||||
    jassert (object != nullptr);
 | 
			
		||||
 | 
			
		||||
    for (auto* o : object->children)
 | 
			
		||||
        list.add (new ValueTree (o));
 | 
			
		||||
    {
 | 
			
		||||
        jassert (o != nullptr);
 | 
			
		||||
        list.add (new ValueTree (*o));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueTree::reorderChildren (const OwnedArray<ValueTree>& newOrder, UndoManager* undoManager)
 | 
			
		||||
@ -1004,7 +1028,7 @@ String ValueTree::toXmlString() const
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void ValueTree::writeToStream (OutputStream& output) const
 | 
			
		||||
{
 | 
			
		||||
    SharedObject::writeObjectToStream (output, object);
 | 
			
		||||
    SharedObject::writeObjectToStream (output, object.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ValueTree ValueTree::readFromStream (InputStream& input)
 | 
			
		||||
@ -1045,7 +1069,7 @@ ValueTree ValueTree::readFromStream (InputStream& input)
 | 
			
		||||
            return v;
 | 
			
		||||
 | 
			
		||||
        v.object->children.add (child.object);
 | 
			
		||||
        child.object->parent = v.object;
 | 
			
		||||
        child.object->parent = v.object.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return v;
 | 
			
		||||
@ -1080,7 +1104,7 @@ public:
 | 
			
		||||
        const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
 | 
			
		||||
 | 
			
		||||
        for (int i = 1 + r.nextInt (numElementsInArray (buffer) - 2); --i >= 0;)
 | 
			
		||||
            buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
 | 
			
		||||
            buffer[i] = chars[r.nextInt (sizeof (chars) - 1)];
 | 
			
		||||
 | 
			
		||||
        String result (buffer);
 | 
			
		||||
 | 
			
		||||
@ -1133,32 +1157,68 @@ public:
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("ValueTree");
 | 
			
		||||
        auto r = getRandom();
 | 
			
		||||
 | 
			
		||||
        for (int i = 10; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            MemoryOutputStream mo;
 | 
			
		||||
            auto v1 = createRandomTree (nullptr, 0, r);
 | 
			
		||||
            v1.writeToStream (mo);
 | 
			
		||||
            beginTest ("ValueTree");
 | 
			
		||||
 | 
			
		||||
            MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
 | 
			
		||||
            auto v2 = ValueTree::readFromStream (mi);
 | 
			
		||||
            expect (v1.isEquivalentTo (v2));
 | 
			
		||||
            auto r = getRandom();
 | 
			
		||||
 | 
			
		||||
            MemoryOutputStream zipped;
 | 
			
		||||
            for (int i = 10; --i >= 0;)
 | 
			
		||||
            {
 | 
			
		||||
                GZIPCompressorOutputStream zippedOut (zipped);
 | 
			
		||||
                v1.writeToStream (zippedOut);
 | 
			
		||||
                MemoryOutputStream mo;
 | 
			
		||||
                auto v1 = createRandomTree (nullptr, 0, r);
 | 
			
		||||
                v1.writeToStream (mo);
 | 
			
		||||
 | 
			
		||||
                MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
 | 
			
		||||
                auto v2 = ValueTree::readFromStream (mi);
 | 
			
		||||
                expect (v1.isEquivalentTo (v2));
 | 
			
		||||
 | 
			
		||||
                MemoryOutputStream zipped;
 | 
			
		||||
                {
 | 
			
		||||
                    GZIPCompressorOutputStream zippedOut (zipped);
 | 
			
		||||
                    v1.writeToStream (zippedOut);
 | 
			
		||||
                }
 | 
			
		||||
                expect (v1.isEquivalentTo (ValueTree::readFromGZIPData (zipped.getData(), zipped.getDataSize())));
 | 
			
		||||
 | 
			
		||||
                std::unique_ptr<XmlElement> xml1 (v1.createXml());
 | 
			
		||||
                std::unique_ptr<XmlElement> xml2 (v2.createCopy().createXml());
 | 
			
		||||
                expect (xml1->isEquivalentTo (xml2.get(), false));
 | 
			
		||||
 | 
			
		||||
                auto v4 = v2.createCopy();
 | 
			
		||||
                expect (v1.isEquivalentTo (v4));
 | 
			
		||||
            }
 | 
			
		||||
            expect (v1.isEquivalentTo (ValueTree::readFromGZIPData (zipped.getData(), zipped.getDataSize())));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            std::unique_ptr<XmlElement> xml1 (v1.createXml());
 | 
			
		||||
            std::unique_ptr<XmlElement> xml2 (v2.createCopy().createXml());
 | 
			
		||||
            expect (xml1->isEquivalentTo (xml2.get(), false));
 | 
			
		||||
        {
 | 
			
		||||
            beginTest ("Float formatting");
 | 
			
		||||
 | 
			
		||||
            auto v4 = v2.createCopy();
 | 
			
		||||
            expect (v1.isEquivalentTo (v4));
 | 
			
		||||
            ValueTree testVT ("Test");
 | 
			
		||||
            Identifier number ("number");
 | 
			
		||||
 | 
			
		||||
            std::map<double, String> tests;
 | 
			
		||||
            tests[1] = "1.0";
 | 
			
		||||
            tests[1.1] = "1.1";
 | 
			
		||||
            tests[1.01] = "1.01";
 | 
			
		||||
            tests[0.76378] = "0.76378";
 | 
			
		||||
            tests[-10] = "-10.0";
 | 
			
		||||
            tests[10.01] = "10.01";
 | 
			
		||||
            tests[0.0123] = "0.0123";
 | 
			
		||||
            tests[-3.7e-27] = "-3.7e-27";
 | 
			
		||||
            tests[1e+40] = "1.0e40";
 | 
			
		||||
            tests[-12345678901234567.0] = "-1.234567890123457e16";
 | 
			
		||||
            tests[192000] = "192000.0";
 | 
			
		||||
            tests[1234567] = "1.234567e6";
 | 
			
		||||
            tests[0.00006] = "0.00006";
 | 
			
		||||
            tests[0.000006] = "6.0e-6";
 | 
			
		||||
 | 
			
		||||
            for (auto& test : tests)
 | 
			
		||||
            {
 | 
			
		||||
                testVT.setProperty (number, test.first, nullptr);
 | 
			
		||||
                auto lines = StringArray::fromLines (testVT.toXmlString());
 | 
			
		||||
                lines.removeEmptyStrings();
 | 
			
		||||
                auto numLines = lines.size();
 | 
			
		||||
                expect (numLines > 1);
 | 
			
		||||
                expectEquals (lines[numLines - 1], "<Test number=\"" + test.second + "\"/>");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -128,18 +128,23 @@ public:
 | 
			
		||||
        @endverbatim
 | 
			
		||||
    */
 | 
			
		||||
    ValueTree (const Identifier& type,
 | 
			
		||||
               std::initializer_list<std::pair<Identifier, var>> properties,
 | 
			
		||||
               std::initializer_list<NamedValueSet::NamedValue> properties,
 | 
			
		||||
               std::initializer_list<ValueTree> subTrees = {});
 | 
			
		||||
 | 
			
		||||
    /** Creates a reference to another ValueTree. */
 | 
			
		||||
    ValueTree (const ValueTree&) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Changes this object to be a reference to the given tree. */
 | 
			
		||||
    ValueTree& operator= (const ValueTree&);
 | 
			
		||||
 | 
			
		||||
    /** Move constructor */
 | 
			
		||||
    ValueTree (ValueTree&&) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Changes this object to be a reference to the given tree.
 | 
			
		||||
        Note that calling this just points this at the new object and invokes the
 | 
			
		||||
        Listener::valueTreeRedirected callback, but it's not an undoable operation. If
 | 
			
		||||
        you're trying to replace an entire tree in an undoable way, you probably want
 | 
			
		||||
        to use copyPropertiesAndChildrenFrom() instead.
 | 
			
		||||
    */
 | 
			
		||||
    ValueTree& operator= (const ValueTree&);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ValueTree();
 | 
			
		||||
 | 
			
		||||
@ -172,6 +177,19 @@ public:
 | 
			
		||||
    /** Returns a deep copy of this tree and all its sub-trees. */
 | 
			
		||||
    ValueTree createCopy() const;
 | 
			
		||||
 | 
			
		||||
    /** Overwrites all the properties in this tree with the properties of the source tree.
 | 
			
		||||
        Any properties that already exist will be updated; and new ones will be added, and
 | 
			
		||||
        any that are not present in the source tree will be removed.
 | 
			
		||||
        @see copyPropertiesAndChildrenFrom
 | 
			
		||||
    */
 | 
			
		||||
    void copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager);
 | 
			
		||||
 | 
			
		||||
    /** Replaces all children and properties of this object with copies of those from
 | 
			
		||||
        the source object.
 | 
			
		||||
        @see copyPropertiesFrom
 | 
			
		||||
    */
 | 
			
		||||
    void copyPropertiesAndChildrenFrom (const ValueTree& source, UndoManager* undoManager);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the type of this tree.
 | 
			
		||||
        The type is specified when the ValueTree is created.
 | 
			
		||||
@ -261,12 +279,6 @@ public:
 | 
			
		||||
    Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager,
 | 
			
		||||
                              bool shouldUpdateSynchronously = false);
 | 
			
		||||
 | 
			
		||||
    /** Overwrites all the properties in this tree with the properties of the source tree.
 | 
			
		||||
        Any properties that already exist will be updated; and new ones will be added, and
 | 
			
		||||
        any that are not present in the source tree will be removed.
 | 
			
		||||
    */
 | 
			
		||||
    void copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the number of child trees inside this one.
 | 
			
		||||
        @see getChild
 | 
			
		||||
@ -388,10 +400,11 @@ public:
 | 
			
		||||
    */
 | 
			
		||||
    struct Iterator
 | 
			
		||||
    {
 | 
			
		||||
        Iterator (const ValueTree&, bool isEnd) noexcept;
 | 
			
		||||
        Iterator& operator++() noexcept;
 | 
			
		||||
        Iterator (const ValueTree&, bool isEnd);
 | 
			
		||||
        Iterator& operator++();
 | 
			
		||||
 | 
			
		||||
        bool operator!= (const Iterator&) const noexcept;
 | 
			
		||||
        bool operator== (const Iterator&) const;
 | 
			
		||||
        bool operator!= (const Iterator&) const;
 | 
			
		||||
        ValueTree operator*() const;
 | 
			
		||||
 | 
			
		||||
        using difference_type    = std::ptrdiff_t;
 | 
			
		||||
@ -462,7 +475,7 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Destructor. */
 | 
			
		||||
        virtual ~Listener() {}
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        /** This method is called when a property of this tree (or of one of its sub-trees) is changed.
 | 
			
		||||
            Note that when you register a listener to a tree, it will receive this callback for
 | 
			
		||||
@ -620,7 +633,8 @@ private:
 | 
			
		||||
    void createListOfChildren (OwnedArray<ValueTree>&) const;
 | 
			
		||||
    void reorderChildren (const OwnedArray<ValueTree>&, UndoManager*);
 | 
			
		||||
 | 
			
		||||
    explicit ValueTree (SharedObject*) noexcept;
 | 
			
		||||
    explicit ValueTree (ReferenceCountedObjectPtr<SharedObject>) noexcept;
 | 
			
		||||
    explicit ValueTree (SharedObject&) noexcept;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ public:
 | 
			
		||||
    ValueTreeSynchroniser (const ValueTree& tree);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    virtual ~ValueTreeSynchroniser();
 | 
			
		||||
    ~ValueTreeSynchroniser() override;
 | 
			
		||||
 | 
			
		||||
    /** This callback happens when the ValueTree changes and the given state-change message
 | 
			
		||||
        needs to be applied to any other trees that need to stay in sync with it.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										100
									
								
								modules/juce_data_structures/values/juce_ValueWithDefault.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								modules/juce_data_structures/values/juce_ValueWithDefault.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   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 5 End-User License
 | 
			
		||||
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
 | 
			
		||||
   27th April 2017).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-5-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-5-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
class ValueWithDefaultTests  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ValueWithDefaultTests() : UnitTest ("ValueWithDefault", "Values") {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("default constructor");
 | 
			
		||||
        {
 | 
			
		||||
            ValueWithDefault vwd;
 | 
			
		||||
            expect (vwd.isUsingDefault());
 | 
			
		||||
            expect (vwd.get() == var());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("missing property");
 | 
			
		||||
        {
 | 
			
		||||
            ValueTree t ("root");
 | 
			
		||||
            ValueWithDefault vwd (t, "testKey", nullptr, "default");
 | 
			
		||||
 | 
			
		||||
            expect (vwd.isUsingDefault());
 | 
			
		||||
            expectEquals (vwd.get().toString(), String ("default"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("non-empty property");
 | 
			
		||||
        {
 | 
			
		||||
            ValueTree t ("root");
 | 
			
		||||
            t.setProperty ("testKey", "non-default", nullptr);
 | 
			
		||||
 | 
			
		||||
            ValueWithDefault vwd (t, "testKey", nullptr, "default");
 | 
			
		||||
 | 
			
		||||
            expect (! vwd.isUsingDefault());
 | 
			
		||||
            expectEquals (vwd.get().toString(), String ("non-default"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("set default");
 | 
			
		||||
        {
 | 
			
		||||
            ValueTree t ("root");
 | 
			
		||||
 | 
			
		||||
            ValueWithDefault vwd (t, "testkey", nullptr);
 | 
			
		||||
            vwd.setDefault ("default");
 | 
			
		||||
 | 
			
		||||
            expect (vwd.isUsingDefault());
 | 
			
		||||
            expectEquals (vwd.get().toString(), String ("default"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("set value");
 | 
			
		||||
        {
 | 
			
		||||
            ValueTree t ("root");
 | 
			
		||||
            t.setProperty ("testkey", "testvalue", nullptr);
 | 
			
		||||
 | 
			
		||||
            ValueWithDefault vwd (t, "testkey", nullptr, "default");
 | 
			
		||||
            vwd = "newvalue";
 | 
			
		||||
 | 
			
		||||
            expect (! vwd.isUsingDefault());
 | 
			
		||||
            expectEquals (t["testkey"].toString(), String ("newvalue"));
 | 
			
		||||
 | 
			
		||||
            vwd.resetToDefault();
 | 
			
		||||
 | 
			
		||||
            expect (vwd.isUsingDefault());
 | 
			
		||||
            expect (t["testkey"] == var());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static ValueWithDefaultTests valueWithDefaultTests;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@ -41,7 +41,7 @@ class ValueWithDefault
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an unitialised ValueWithDefault. Initialise it using one of the referTo() methods. */
 | 
			
		||||
    ValueWithDefault()    : undoManager (nullptr) {}
 | 
			
		||||
    ValueWithDefault() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates an ValueWithDefault object. The default value will be an empty var. */
 | 
			
		||||
    ValueWithDefault (ValueTree& tree, const Identifier& propertyID, UndoManager* um)
 | 
			
		||||
@ -121,13 +121,13 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the property does not exist or is empty. */
 | 
			
		||||
    /** Returns true if the property does not exist in the referenced ValueTree. */
 | 
			
		||||
    bool isUsingDefault() const
 | 
			
		||||
    {
 | 
			
		||||
        return ! targetTree.hasProperty (targetProperty);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Resets the property to an empty var. */
 | 
			
		||||
    /** Removes the property from the referenced ValueTree. */
 | 
			
		||||
    void resetToDefault() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        targetTree.removeProperty (targetProperty, nullptr);
 | 
			
		||||
@ -181,17 +181,29 @@ public:
 | 
			
		||||
    /** 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;
 | 
			
		||||
    UndoManager* undoManager = nullptr;
 | 
			
		||||
    var defaultValue;
 | 
			
		||||
 | 
			
		||||
    String delimiter;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void referToWithDefault (ValueTree& v, const Identifier& i, UndoManager* um,
 | 
			
		||||
    void referToWithDefault (const ValueTree& v, const Identifier& i, UndoManager* um,
 | 
			
		||||
                             const var& defaultVal, StringRef del)
 | 
			
		||||
    {
 | 
			
		||||
        targetTree = v;
 | 
			
		||||
@ -209,6 +221,7 @@ private:
 | 
			
		||||
        jassert (delimiter.isNotEmpty());
 | 
			
		||||
 | 
			
		||||
        StringArray elements;
 | 
			
		||||
 | 
			
		||||
        for (auto& v : input)
 | 
			
		||||
            elements.add (v.toString());
 | 
			
		||||
 | 
			
		||||
@ -224,6 +237,9 @@ private:
 | 
			
		||||
 | 
			
		||||
        return arr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_WEAK_REFERENCEABLE (ValueWithDefault)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user