1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
29 //==============================================================================
30 /**
31     A powerful tree structure that can be used to hold free-form data, and which can
32     handle its own undo and redo behaviour.
33 
34     A ValueTree contains a list of named properties as var objects, and also holds
35     any number of sub-trees.
36 
37     Create ValueTree objects on the stack, and don't be afraid to copy them around, as
38     they're simply a lightweight reference to a shared data container. Creating a copy
39     of another ValueTree simply creates a new reference to the same underlying object - to
40     make a separate, deep copy of a tree you should explicitly call createCopy().
41 
42     Each ValueTree has a type name, in much the same way as an XmlElement has a tag name,
43     and much of the structure of a ValueTree is similar to an XmlElement tree.
44     You can convert a ValueTree to and from an XmlElement, and as long as the XML doesn't
45     contain text elements, the conversion works well and makes a good serialisation
46     format. They can also be serialised to a binary format, which is very fast and compact.
47 
48     All the methods that change data take an optional UndoManager, which will be used
49     to track any changes to the object. For this to work, you have to be careful to
50     consistently always use the same UndoManager for all operations to any sub-tree inside
51     the tree.
52 
53     A ValueTree can only be a child of one parent at a time, so if you're moving one from
54     one tree to another, be careful to always remove it first, before adding it. This
55     could also mess up your undo/redo chain, so be wary! In a debug build you should hit
56     assertions if you try to do anything dangerous, but there are still plenty of ways it
57     could go wrong.
58 
59     Note that although the children in a tree have a fixed order, the properties are not
60     guaranteed to be stored in any particular order, so don't expect that a property's index
61     will correspond to the order in which the property was added, or that it will remain
62     constant when other properties are added or removed.
63 
64     Listeners can be added to a ValueTree to be told when properties change and when
65     sub-trees are added or removed.
66 
67     @see var, XmlElement
68 
69     @tags{DataStructures}
70 */
71 class JUCE_API  ValueTree  final
72 {
73 public:
74     //==============================================================================
75     /** Creates an empty, invalid ValueTree.
76 
77         A ValueTree that is created with this constructor can't actually be used for anything,
78         it's just a default 'null' ValueTree that can be returned to indicate some sort of failure.
79         To create a real one, use the constructor that takes a string.
80     */
81     ValueTree() noexcept;
82 
83     /** Creates an empty ValueTree with the given type name.
84 
85         Like an XmlElement, each ValueTree has a type, which you can access with
86         getType() and hasType().
87     */
88     explicit ValueTree (const Identifier& type);
89 
90     /** Creates a value tree from nested lists of properties and ValueTrees.
91 
92         This code,
93 
94         @code
95         ValueTree groups
96         { "ParameterGroups", {},
97           {
98             { "Group", {{ "name", "Tone Controls" }},
99               {
100                 { "Parameter", {{ "id", "distortion" }, { "value", 0.5 }}},
101                 { "Parameter", {{ "id", "reverb" },     { "value", 0.5 }}}
102               }
103             },
104             { "Group", {{ "name", "Other Controls" }},
105               {
106                 { "Parameter", {{ "id", "drywet" }, { "value", 0.5 }}},
107                 { "Parameter", {{ "id", "gain" },   { "value", 0.5 }}}
108               }
109             }
110           }
111         };
112         @endcode
113 
114         produces this tree:
115 
116         @verbatim
117         <ParameterGroups>
118           <Group name="Tone Controls">
119             <Parameter id="distortion" value="0.5"/>
120             <Parameter id="reverb" value="0.5"/>
121           </Group>
122           <Group name="Other Controls">
123             <Parameter id="drywet" value="0.5"/>
124             <Parameter id="gain" value="0.5"/>
125           </Group>
126         </ParameterGroups>
127         @endverbatim
128     */
129     ValueTree (const Identifier& type,
130                std::initializer_list<NamedValueSet::NamedValue> properties,
131                std::initializer_list<ValueTree> subTrees = {});
132 
133     /** Creates a reference to another ValueTree. */
134     ValueTree (const ValueTree&) noexcept;
135 
136     /** Move constructor */
137     ValueTree (ValueTree&&) noexcept;
138 
139     /** Changes this object to be a reference to the given tree.
140         Note that calling this just points this at the new object and invokes the
141         Listener::valueTreeRedirected callback, but it's not an undoable operation. If
142         you're trying to replace an entire tree in an undoable way, you probably want
143         to use copyPropertiesAndChildrenFrom() instead.
144     */
145     ValueTree& operator= (const ValueTree&);
146 
147     /** Destructor. */
148     ~ValueTree();
149 
150     /** Returns true if both this and the other tree refer to the same underlying structure.
151         Note that this isn't a value comparison - two independently-created trees which
152         contain identical data are NOT considered equal.
153     */
154     bool operator== (const ValueTree&) const noexcept;
155 
156     /** Returns true if this and the other tree refer to different underlying structures.
157         Note that this isn't a value comparison - two independently-created trees which
158         contain identical data are not considered equal.
159     */
160     bool operator!= (const ValueTree&) const noexcept;
161 
162     /** Performs a deep comparison between the properties and children of two trees.
163         If all the properties and children of the two trees are the same (recursively), this
164         returns true.
165         The normal operator==() only checks whether two trees refer to the same shared data
166         structure, so use this method if you need to do a proper value comparison.
167     */
168     bool isEquivalentTo (const ValueTree&) const;
169 
170     //==============================================================================
171     /** Returns true if this tree refers to some valid data.
172         An invalid tree is one that was created with the default constructor.
173     */
isValid()174     bool isValid() const noexcept                           { return object != nullptr; }
175 
176     /** Returns a deep copy of this tree and all its sub-trees. */
177     ValueTree createCopy() const;
178 
179     /** Overwrites all the properties in this tree with the properties of the source tree.
180         Any properties that already exist will be updated; and new ones will be added, and
181         any that are not present in the source tree will be removed.
182         @see copyPropertiesAndChildrenFrom
183     */
184     void copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager);
185 
186     /** Replaces all children and properties of this object with copies of those from
187         the source object.
188         @see copyPropertiesFrom
189     */
190     void copyPropertiesAndChildrenFrom (const ValueTree& source, UndoManager* undoManager);
191 
192     //==============================================================================
193     /** Returns the type of this tree.
194         The type is specified when the ValueTree is created.
195         @see hasType
196     */
197     Identifier getType() const noexcept;
198 
199     /** Returns true if the tree has this type.
200         The comparison is case-sensitive.
201         @see getType
202     */
203     bool hasType (const Identifier& typeName) const noexcept;
204 
205     //==============================================================================
206     /** Returns the value of a named property.
207         If no such property has been set, this will return a void variant.
208         You can also use operator[] to get a property.
209         @see var, setProperty, getPropertyPointer, hasProperty
210     */
211     const var& getProperty (const Identifier& name) const noexcept;
212 
213     /** Returns the value of a named property, or the value of defaultReturnValue
214         if the property doesn't exist.
215         You can also use operator[] and getProperty to get a property.
216         @see var, getProperty, getPropertyPointer, setProperty, hasProperty
217     */
218     var getProperty (const Identifier& name, const var& defaultReturnValue) const;
219 
220     /** Returns a pointer to the value of a named property, or nullptr if the property
221         doesn't exist.
222         @see var, getProperty, setProperty, hasProperty
223     */
224     const var* getPropertyPointer (const Identifier& name) const noexcept;
225 
226     /** Returns the value of a named property.
227         If no such property has been set, this will return a void variant. This is the same as
228         calling getProperty().
229         @see getProperty
230     */
231     const var& operator[] (const Identifier& name) const noexcept;
232 
233     /** Changes a named property of the tree.
234         The name identifier must not be an empty string.
235         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
236         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
237         @see var, getProperty, removeProperty
238         @returns a reference to the value tree, so that you can daisy-chain calls to this method.
239     */
240     ValueTree& setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager);
241 
242     /** Returns true if the tree contains a named property. */
243     bool hasProperty (const Identifier& name) const noexcept;
244 
245     /** Removes a property from the tree.
246         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
247         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
248     */
249     void removeProperty (const Identifier& name, UndoManager* undoManager);
250 
251     /** Removes all properties from the tree.
252         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
253         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
254     */
255     void removeAllProperties (UndoManager* undoManager);
256 
257     /** Returns the total number of properties that the tree contains.
258         @see getProperty.
259     */
260     int getNumProperties() const noexcept;
261 
262     /** Returns the identifier of the property with a given index.
263         Note that properties are not guaranteed to be stored in any particular order, so don't
264         expect that the index will correspond to the order in which the property was added, or
265         that it will remain constant when other properties are added or removed.
266         @see getNumProperties
267     */
268     Identifier getPropertyName (int index) const noexcept;
269 
270     /** Returns a Value object that can be used to control and respond to one of the tree's properties.
271 
272         The Value object will maintain a reference to this tree, and will use the undo manager when
273         it needs to change the value. Attaching a Value::Listener to the value object will provide
274         callbacks whenever the property changes.
275         If shouldUpdateSynchronously is true the Value::Listener will be updated synchronously.
276         @see ValueSource::sendChangeMessage (bool)
277     */
278     Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager,
279                               bool shouldUpdateSynchronously = false);
280 
281     //==============================================================================
282     /** Returns the number of child trees inside this one.
283         @see getChild
284     */
285     int getNumChildren() const noexcept;
286 
287     /** Returns one of this tree's sub-trees.
288         If the index is out of range, it'll return an invalid tree. (You can use isValid() to
289         check whether a tree is valid)
290     */
291     ValueTree getChild (int index) const;
292 
293     /** Returns the first sub-tree with the specified type name.
294         If no such child tree exists, it'll return an invalid tree. (You can use isValid() to
295         check whether a tree is valid)
296         @see getOrCreateChildWithName
297     */
298     ValueTree getChildWithName (const Identifier& type) const;
299 
300     /** Returns the first sub-tree with the specified type name, creating and adding
301         a child with this name if there wasn't already one there.
302         The only time this will return an invalid object is when the object that you're calling
303         the method on is itself invalid.
304         @see getChildWithName
305     */
306     ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager);
307 
308     /** Looks for the first sub-tree that has the specified property value.
309         This will scan the child trees in order, until it finds one that has property that matches
310         the specified value.
311         If no such tree is found, it'll return an invalid object. (You can use isValid() to
312         check whether a tree is valid)
313     */
314     ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const;
315 
316     /** Adds a child to this tree.
317         Make sure that the child being added has first been removed from any former parent before
318         calling this, or else you'll hit an assertion.
319         If the index is < 0 or greater than the current number of sub-trees, the new one will be
320         added at the end of the list.
321         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
322         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
323         @see appendChild, removeChild
324     */
325     void addChild (const ValueTree& child, int index, UndoManager* undoManager);
326 
327     /** Appends a new child sub-tree to this tree.
328         This is equivalent to calling addChild() with an index of -1. See addChild() for more details.
329         @see addChild, removeChild
330     */
331     void appendChild (const ValueTree& child, UndoManager* undoManager);
332 
333     /** Removes the specified child from this tree's child-list.
334         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
335         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
336     */
337     void removeChild (const ValueTree& child, UndoManager* undoManager);
338 
339     /** Removes a sub-tree from this tree.
340         If the index is out-of-range, nothing will be changed.
341         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
342         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
343     */
344     void removeChild (int childIndex, UndoManager* undoManager);
345 
346     /** Removes all child-trees.
347         If the undoManager parameter is not nullptr, its UndoManager::perform() method will be used,
348         so that this change can be undone. Be very careful not to mix undoable and non-undoable changes!
349     */
350     void removeAllChildren (UndoManager* undoManager);
351 
352     /** Moves one of the sub-trees to a different index.
353         This will move the child to a specified index, shuffling along any intervening
354         items as required. So for example, if you have a list of { 0, 1, 2, 3, 4, 5 }, then
355         calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
356 
357         @param currentIndex     the index of the item to be moved. If this isn't a
358                                 valid index, then nothing will be done
359         @param newIndex         the index at which you'd like this item to end up. If this
360                                 is less than zero, the value will be moved to the end
361                                 of the list
362         @param undoManager      the optional UndoManager to use to store this transaction
363     */
364     void moveChild (int currentIndex, int newIndex, UndoManager* undoManager);
365 
366     /** Returns true if this tree is a sub-tree (at any depth) of the given parent.
367         This searches recursively, so returns true if it's a sub-tree at any level below the parent.
368     */
369     bool isAChildOf (const ValueTree& possibleParent) const noexcept;
370 
371     /** Returns the index of a child item in this parent.
372         If the child isn't found, this returns -1.
373     */
374     int indexOf (const ValueTree& child) const noexcept;
375 
376     /** Returns the parent tree that contains this one.
377         If the tree has no parent, this will return an invalid object. (You can use isValid() to
378         check whether a tree is valid)
379     */
380     ValueTree getParent() const noexcept;
381 
382     /** Recursively finds the highest-level parent tree that contains this one.
383         If the tree has no parent, this will return itself.
384     */
385     ValueTree getRoot() const noexcept;
386 
387     /** Returns one of this tree's siblings in its parent's child list.
388         The delta specifies how far to move through the list, so a value of 1 would return the tree
389         that follows this one, -1 would return the tree before it, 0 will return this one, etc.
390         If the requested position is beyond the start or end of the child list, this will return an
391         invalid object.
392     */
393     ValueTree getSibling (int delta) const noexcept;
394 
395     //==============================================================================
396     /** Iterator for a ValueTree.
397         You shouldn't ever need to use this class directly - it's used internally by ValueTree::begin()
398         and ValueTree::end() to allow range-based-for loops on a ValueTree.
399     */
400     struct Iterator
401     {
402         Iterator (const ValueTree&, bool isEnd);
403         Iterator& operator++();
404 
405         bool operator== (const Iterator&) const;
406         bool operator!= (const Iterator&) const;
407         ValueTree operator*() const;
408 
409         using difference_type    = std::ptrdiff_t;
410         using value_type         = ValueTree;
411         using reference          = ValueTree&;
412         using pointer            = ValueTree*;
413         using iterator_category  = std::forward_iterator_tag;
414 
415     private:
416         void* internal;
417     };
418 
419     /** Returns a start iterator for the children in this tree. */
420     Iterator begin() const noexcept;
421 
422     /** Returns an end iterator for the children in this tree. */
423     Iterator end() const noexcept;
424 
425     //==============================================================================
426     /** Creates an XmlElement that holds a complete image of this tree and all its children.
427         If this tree is invalid, this may return nullptr. Otherwise, the XML that is produced can
428         be used to recreate a similar tree by calling ValueTree::fromXml().
429         @see fromXml, toXmlString
430     */
431     std::unique_ptr<XmlElement> createXml() const;
432 
433     /** Tries to recreate a tree from its XML representation.
434         This isn't designed to cope with random XML data - it should only be fed XML that was created
435         by the createXml() method.
436     */
437     static ValueTree fromXml (const XmlElement& xml);
438 
439     /** Tries to recreate a tree from its XML representation.
440         This isn't designed to cope with random XML data - it should only be fed XML that was created
441         by the createXml() method.
442     */
443     static ValueTree fromXml (const String& xmlText);
444 
445     /** This returns a string containing an XML representation of the tree.
446         This is quite handy for debugging purposes, as it provides a quick way to view a tree.
447         @see createXml()
448     */
449     String toXmlString (const XmlElement::TextFormat& format = {}) const;
450 
451     //==============================================================================
452     /** Stores this tree (and all its children) in a binary format.
453 
454         Once written, the data can be read back with readFromStream().
455 
456         It's much faster to load/save your tree in binary form than as XML, but
457         obviously isn't human-readable.
458     */
459     void writeToStream (OutputStream& output) const;
460 
461     /** Reloads a tree from a stream that was written with writeToStream(). */
462     static ValueTree readFromStream (InputStream& input);
463 
464     /** Reloads a tree from a data block that was written with writeToStream(). */
465     static ValueTree readFromData (const void* data, size_t numBytes);
466 
467     /** Reloads a tree from a data block that was written with writeToStream() and
468         then zipped using GZIPCompressorOutputStream.
469     */
470     static ValueTree readFromGZIPData (const void* data, size_t numBytes);
471 
472     //==============================================================================
473     /** Listener class for events that happen to a ValueTree.
474 
475         To get events from a ValueTree, make your class implement this interface, and use
476         ValueTree::addListener() and ValueTree::removeListener() to register it.
477     */
478     class JUCE_API  Listener
479     {
480     public:
481         /** Destructor. */
482         virtual ~Listener() = default;
483 
484         /** This method is called when a property of this tree (or of one of its sub-trees) is changed.
485             Note that when you register a listener to a tree, it will receive this callback for
486             property changes in that tree, and also for any of its children, (recursively, at any depth).
487             If your tree has sub-trees but you only want to know about changes to the top level tree,
488             simply check the tree parameter in this callback to make sure it's the tree you're interested in.
489         */
490         virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged,
491                                                const Identifier& property);
492 
493         /** This method is called when a child sub-tree is added.
494             Note that when you register a listener to a tree, it will receive this callback for
495             child changes in both that tree and any of its children, (recursively, at any depth).
496             If your tree has sub-trees but you only want to know about changes to the top level tree,
497             just check the parentTree parameter to make sure it's the one that you're interested in.
498         */
499         virtual void valueTreeChildAdded (ValueTree& parentTree,
500                                           ValueTree& childWhichHasBeenAdded);
501 
502         /** This method is called when a child sub-tree is removed.
503 
504             Note that when you register a listener to a tree, it will receive this callback for
505             child changes in both that tree and any of its children, (recursively, at any depth).
506             If your tree has sub-trees but you only want to know about changes to the top level tree,
507             just check the parentTree parameter to make sure it's the one that you're interested in.
508         */
509         virtual void valueTreeChildRemoved (ValueTree& parentTree,
510                                             ValueTree& childWhichHasBeenRemoved,
511                                             int indexFromWhichChildWasRemoved);
512 
513         /** This method is called when a tree's children have been re-shuffled.
514 
515             Note that when you register a listener to a tree, it will receive this callback for
516             child changes in both that tree and any of its children, (recursively, at any depth).
517             If your tree has sub-trees but you only want to know about changes to the top level tree,
518             just check the parameter to make sure it's the tree that you're interested in.
519         */
520         virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved,
521                                                  int oldIndex, int newIndex);
522 
523         /** This method is called when a tree has been added or removed from a parent.
524 
525             This callback happens when the tree to which the listener was registered is added or
526             removed from a parent. Unlike the other callbacks, it applies only to the tree to which
527             the listener is registered, and not to any of its children.
528         */
529         virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged);
530 
531         /** This method is called when a tree is made to point to a different internal shared object.
532             When operator= is used to make a ValueTree refer to a different object, this callback
533             will be made.
534         */
535         virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged);
536     };
537 
538     /** Adds a listener to receive callbacks when this tree is changed in some way.
539 
540         The listener is added to this specific ValueTree object, and not to the shared
541         object that it refers to. When this object is deleted, all the listeners will
542         be lost, even if other references to the same ValueTree still exist. And if you
543         use the operator= to make this refer to a different ValueTree, any listeners will
544         begin listening to changes to the new tree instead of the old one.
545 
546         When you're adding a listener, make sure that you add it to a ValueTree instance that
547         will last for as long as you need the listener. In general, you'd never want to add a
548         listener to a local stack-based ValueTree, and would usually add one to a member variable.
549 
550         @see removeListener
551     */
552     void addListener (Listener* listener);
553 
554     /** Removes a listener that was previously added with addListener(). */
555     void removeListener (Listener* listener);
556 
557     /** Changes a named property of the tree, but will not notify a specified listener of the change.
558         @see setProperty
559     */
560     ValueTree& setPropertyExcludingListener (Listener* listenerToExclude,
561                                              const Identifier& name, const var& newValue,
562                                              UndoManager* undoManager);
563 
564     /** Causes a property-change callback to be triggered for the specified property,
565         calling any listeners that are registered.
566     */
567     void sendPropertyChangeMessage (const Identifier& property);
568 
569     //==============================================================================
570     /** This method uses a comparator object to sort the tree's children into order.
571 
572         The object provided must have a method of the form:
573         @code
574         int compareElements (const ValueTree& first, const ValueTree& second);
575         @endcode
576 
577         ..and this method must return:
578           - a value of < 0 if the first comes before the second
579           - a value of 0 if the two objects are equivalent
580           - a value of > 0 if the second comes before the first
581 
582         To improve performance, the compareElements() method can be declared as static or const.
583 
584         @param comparator   the comparator to use for comparing elements.
585         @param undoManager  optional UndoManager for storing the changes
586         @param retainOrderOfEquivalentItems     if this is true, then items which the comparator says are
587                             equivalent will be kept in the order in which they currently appear in the array.
588                             This is slower to perform, but may be important in some cases. If it's false, a
589                             faster algorithm is used, but equivalent elements may be rearranged.
590     */
591     template <typename ElementComparator>
sort(ElementComparator & comparator,UndoManager * undoManager,bool retainOrderOfEquivalentItems)592     void sort (ElementComparator& comparator, UndoManager* undoManager, bool retainOrderOfEquivalentItems)
593     {
594         if (object != nullptr)
595         {
596             OwnedArray<ValueTree> sortedList;
597             createListOfChildren (sortedList);
598             ComparatorAdapter<ElementComparator> adapter (comparator);
599             sortedList.sort (adapter, retainOrderOfEquivalentItems);
600             reorderChildren (sortedList, undoManager);
601         }
602     }
603 
604     /** Returns the total number of references to the shared underlying data structure that this
605         ValueTree is using.
606     */
607     int getReferenceCount() const noexcept;
608 
609     /* An invalid ValueTree that can be used if you need to return one as an error condition, etc.
610         @deprecated If you need an empty ValueTree object, just use ValueTree() or {}.
611     */
612     JUCE_DEPRECATED_STATIC (static const ValueTree invalid;)
613 
614 private:
615     //==============================================================================
616     JUCE_PUBLIC_IN_DLL_BUILD (class SharedObject)
617     friend class SharedObject;
618 
619     ReferenceCountedObjectPtr<SharedObject> object;
620     ListenerList<Listener> listeners;
621 
622     template <typename ElementComparator>
623     struct ComparatorAdapter
624     {
ComparatorAdapterComparatorAdapter625         ComparatorAdapter (ElementComparator& comp) noexcept : comparator (comp) {}
626 
compareElementsComparatorAdapter627         int compareElements (const ValueTree* const first, const ValueTree* const second)
628         {
629             return comparator.compareElements (*first, *second);
630         }
631 
632     private:
633         ElementComparator& comparator;
634         JUCE_DECLARE_NON_COPYABLE (ComparatorAdapter)
635     };
636 
637     void createListOfChildren (OwnedArray<ValueTree>&) const;
638     void reorderChildren (const OwnedArray<ValueTree>&, UndoManager*);
639 
640     explicit ValueTree (ReferenceCountedObjectPtr<SharedObject>) noexcept;
641     explicit ValueTree (SharedObject&) noexcept;
642 };
643 
644 } // namespace juce
645