Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_ValueTree.h 30KB

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