| 
				
				
					
				
				
				 | 
			
			 | 
			@@ -27,18 +27,16 @@ class ValueTree::SharedObject  : public ReferenceCountedObject | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			public:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    typedef ReferenceCountedObjectPtr<SharedObject> Ptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    explicit SharedObject (const Identifier& t) noexcept
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        : type (t), parent (nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    explicit SharedObject (const Identifier& t) noexcept  : type (t)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    SharedObject (const SharedObject& other)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        : ReferenceCountedObject(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			          type (other.type), properties (other.properties), parent (nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        : ReferenceCountedObject(), type (other.type), properties (other.properties)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int i = 0; i < other.children.size(); ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            SharedObject* const child = new SharedObject (*other.children.getObjectPointerUnchecked(i));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            auto child = new SharedObject (*other.children.getObjectPointerUnchecked(i));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            child->parent = this;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            children.add (child);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -62,132 +60,62 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return parent == nullptr ? this : parent->getRoot();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Method>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void callListeners (Method method, ValueTree& tree) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Function>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void callListeners (Function fn) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const int numListeners = valueTreesWithListeners.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        auto numListeners = valueTreesWithListeners.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (numListeners == 1)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            valueTreesWithListeners.getUnchecked(0)->listeners.call (method, tree);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            fn (valueTreesWithListeners.getUnchecked(0)->listeners);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else if (numListeners > 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            const SortedSet<ValueTree*> listenersCopy (valueTreesWithListeners);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            auto listenersCopy = valueTreesWithListeners;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            for (int i = 0; i < numListeners; ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                ValueTree* const v = listenersCopy.getUnchecked(i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                auto* v = listenersCopy.getUnchecked(i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (i == 0 || valueTreesWithListeners.contains (v))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    v->listeners.call (method, tree);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    fn (v->listeners);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Method, typename ParamType>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void callListeners (Method method, ValueTree& tree, ParamType& param2) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Function>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void callListenersForAllParents (Function fn) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const int numListeners = valueTreesWithListeners.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (numListeners == 1)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            valueTreesWithListeners.getUnchecked(0)->listeners.call (method, tree, param2);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else if (numListeners > 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            const SortedSet<ValueTree*> listenersCopy (valueTreesWithListeners);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            for (int i = 0; i < numListeners; ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                ValueTree* const v = listenersCopy.getUnchecked(i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (i == 0 || valueTreesWithListeners.contains (v))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    v->listeners.call (method, tree, param2);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Method, typename ParamType>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void callListenersExcluding (ValueTree::Listener* listenerToExclude,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                 Method method, ValueTree& tree, ParamType& param2) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const int numListeners = valueTreesWithListeners.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (numListeners == 1)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            valueTreesWithListeners.getUnchecked(0)->listeners.callExcluding (*listenerToExclude, method, tree, param2);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else if (numListeners > 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            const SortedSet<ValueTree*> listenersCopy (valueTreesWithListeners);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            for (int i = 0; i < numListeners; ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                ValueTree* const v = listenersCopy.getUnchecked(i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (i == 0 || valueTreesWithListeners.contains (v))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    v->listeners.callExcluding (*listenerToExclude, method, tree, param2);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    template <typename Method, typename ParamType1, typename ParamType2>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void callListeners (Method method, ValueTree& tree, ParamType1& param2, ParamType2& param3) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        const int numListeners = valueTreesWithListeners.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (numListeners == 1)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            valueTreesWithListeners.getUnchecked(0)->listeners.call (method, tree, param2, param3);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else if (numListeners > 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            const SortedSet<ValueTree*> listenersCopy (valueTreesWithListeners);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            for (int i = 0; i < numListeners; ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                ValueTree* const v = listenersCopy.getUnchecked(i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (i == 0 || valueTreesWithListeners.contains (v))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    v->listeners.call (method, tree, param2, param3);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (auto* t = this; t != nullptr; t = t->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            t->callListeners (fn);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void sendPropertyChangeMessage (const Identifier& property, ValueTree::Listener* listenerToExclude = nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        ValueTree tree (this);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (listenerToExclude == nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                t->callListeners (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            else
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                t->callListenersExcluding (listenerToExclude, &ValueTree::Listener::valueTreePropertyChanged, tree, property);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (listenerToExclude == nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            callListenersForAllParents ([&] (ListenerList<Listener>& list) { list.call (&ValueTree::Listener::valueTreePropertyChanged, tree, property); });
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            callListenersForAllParents ([&] (ListenerList<Listener>& list) { list.callExcluding (*listenerToExclude, &ValueTree::Listener::valueTreePropertyChanged, tree, property); });
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void sendChildAddedMessage (ValueTree child)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        ValueTree tree (this);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            t->callListeners (&ValueTree::Listener::valueTreeChildAdded, tree, child);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        callListenersForAllParents ([&] (ListenerList<Listener>& list) { list.call (&ValueTree::Listener::valueTreeChildAdded, tree, child); });
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void sendChildRemovedMessage (ValueTree child, int index)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        ValueTree tree (this);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            t->callListeners (&ValueTree::Listener::valueTreeChildRemoved, tree, child, index);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        callListenersForAllParents ([=, &tree, &child] (ListenerList<Listener>& list) { list.call (&ValueTree::Listener::valueTreeChildRemoved, tree, child, index); });
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void sendChildOrderChangedMessage (int oldIndex, int newIndex)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        ValueTree tree (this);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            t->callListeners (&ValueTree::Listener::valueTreeChildOrderChanged, tree, oldIndex, newIndex);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        callListenersForAllParents ([=, &tree] (ListenerList<Listener>& list) { list.call (&ValueTree::Listener::valueTreeChildOrderChanged, tree, oldIndex, newIndex); });
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void sendParentChangeMessage()
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -195,10 +123,10 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        ValueTree tree (this);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int j = children.size(); --j >= 0;)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (SharedObject* const child = children.getObjectPointer (j))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (auto* child = children.getObjectPointer (j))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                child->sendParentChangeMessage();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        callListeners (&ValueTree::Listener::valueTreeParentChanged, tree);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        callListeners ([&] (ListenerList<Listener>& list) { list.call (&ValueTree::Listener::valueTreeParentChanged, tree); });
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    void setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager,
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -211,14 +139,14 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (const var* const existingValue = properties.getVarPointer (name))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (auto* existingValue = properties.getVarPointer (name))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (*existingValue != newValue)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue, false, false, listenerToExclude));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            else
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                undoManager->perform (new SetPropertyAction (this, name, newValue, var(), true, false, listenerToExclude));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                undoManager->perform (new SetPropertyAction (this, name, newValue, {}, true, false, listenerToExclude));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -238,7 +166,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (properties.contains (name))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                undoManager->perform (new SetPropertyAction (this, name, var(), properties [name], false, true));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                undoManager->perform (new SetPropertyAction (this, name, {}, properties [name], false, true));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -248,7 +176,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            while (properties.size() > 0)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                const Identifier name (properties.getName (properties.size() - 1));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                auto name = properties.getName (properties.size() - 1);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                properties.remove (name);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                sendPropertyChangeMessage (name);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            }
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -256,7 +184,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        else
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            for (int i = properties.size(); --i >= 0;)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                undoManager->perform (new SetPropertyAction (this, properties.getName(i), var(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                undoManager->perform (new SetPropertyAction (this, properties.getName(i), {},
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                                             properties.getValueAt(i), false, true));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -273,26 +201,20 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ValueTree getChildWithName (const Identifier& typeToMatch) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int i = 0; i < children.size(); ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            SharedObject* const s = children.getObjectPointerUnchecked (i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (auto* s : children)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (s->type == typeToMatch)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return ValueTree (s);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return ValueTree();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return {};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ValueTree getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int i = 0; i < children.size(); ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            SharedObject* const s = children.getObjectPointerUnchecked (i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (auto* s : children)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (s->type == typeToMatch)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return ValueTree (s);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        SharedObject* const newObject = new SharedObject (typeToMatch);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        auto newObject = new SharedObject (typeToMatch);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        addChild (newObject, -1, undoManager);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return ValueTree (newObject);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -300,19 +222,16 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int i = 0; i < children.size(); ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            SharedObject* const s = children.getObjectPointerUnchecked (i);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (auto* s : children)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (s->properties[propertyName] == propertyValue)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return ValueTree (s);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return ValueTree();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return {};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    bool isAChildOf (const SharedObject* const possibleParent) const noexcept
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (const SharedObject* p = parent; p != nullptr; p = p->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (auto* p = parent; p != nullptr; p = p->parent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (p == possibleParent)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -418,7 +337,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (int i = 0; i < children.size(); ++i)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            SharedObject* const child = newOrder.getUnchecked(i)->object;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            auto* child = newOrder.getUnchecked(i)->object.get();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (children.getObjectPointerUnchecked (i) != child)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            {
 | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -446,7 +365,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    XmlElement* createXml() const
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        XmlElement* const 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)
 | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -629,7 +548,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        UndoableAction* createCoalescedAction (UndoableAction* nextAction) override
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (MoveChildAction* next = dynamic_cast<MoveChildAction*> (nextAction))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (auto* next = dynamic_cast<MoveChildAction*> (nextAction))
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (next->parent == parent && next->startIndex == endIndex)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    return new MoveChildAction (parent, startIndex, next->endIndex);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -648,7 +567,7 @@ public: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    NamedValueSet properties;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ReferenceCountedArray<SharedObject> children;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    SortedSet<ValueTree*> valueTreesWithListeners;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    SharedObject* parent;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    SharedObject* parent = nullptr;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			private:
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    SharedObject& operator= (const SharedObject&);
 | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -760,7 +679,7 @@ ValueTree ValueTree::getRoot() const noexcept | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			ValueTree ValueTree::getSibling (const int delta) const noexcept
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (object == nullptr || object->parent == nullptr)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return ValueTree();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return {};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    const int index = object->parent->indexOf (*this) + delta;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return ValueTree (object->parent->children.getObjectPointer (index));
 | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -1054,7 +973,7 @@ ValueTree ValueTree::fromXml (const XmlElement& xml) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // ValueTrees don't have any equivalent to XML text elements!
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    jassertfalse;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return ValueTree();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return {};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			String ValueTree::toXmlString() const
 | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -1071,10 +990,10 @@ void ValueTree::writeToStream (OutputStream& output) const | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			ValueTree ValueTree::readFromStream (InputStream& input)
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    const String type (input.readString());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    auto type = input.readString();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (type.isEmpty())
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return ValueTree();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return {};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ValueTree v (type);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
				| 
				
					
				
				
				
				 | 
			
			 | 
			
  |