The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

506 lines
22KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_VALUETREE_JUCEHEADER__
  19. #define __JUCE_VALUETREE_JUCEHEADER__
  20. #include "juce_NamedValueSet.h"
  21. #include "juce_Value.h"
  22. #include "../utilities/juce_UndoManager.h"
  23. #include "../text/juce_XmlElement.h"
  24. #include "../events/juce_ListenerList.h"
  25. #include "juce_ReferenceCountedArray.h"
  26. //==============================================================================
  27. /**
  28. A powerful tree structure that can be used to hold free-form data, and which can
  29. handle its own undo and redo behaviour.
  30. A ValueTree contains a list of named properties as var objects, and also holds
  31. any number of sub-trees.
  32. Create ValueTree objects on the stack, and don't be afraid to copy them around, as
  33. they're simply a lightweight reference to a shared data container. Creating a copy
  34. of another ValueTree simply creates a new reference to the same underlying object - to
  35. make a separate, deep copy of a tree you should explicitly call createCopy().
  36. Each ValueTree has a type name, in much the same way as an XmlElement has a tag name,
  37. and much of the structure of a ValueTree is similar to an XmlElement tree.
  38. You can convert a ValueTree to and from an XmlElement, and as long as the XML doesn't
  39. contain text elements, the conversion works well and makes a good serialisation
  40. format. They can also be serialised to a binary format, which is very fast and compact.
  41. All the methods that change data take an optional UndoManager, which will be used
  42. to track any changes to the object. For this to work, you have to be careful to
  43. consistently always use the same UndoManager for all operations to any node inside
  44. the tree.
  45. A ValueTree can only be a child of one parent at a time, so if you're moving one from
  46. one tree to another, be careful to always remove it first, before adding it. This
  47. could also mess up your undo/redo chain, so be wary! In a debug build you should hit
  48. assertions if you try to do anything dangerous, but there are still plenty of ways it
  49. could go wrong.
  50. Listeners can be added to a ValueTree to be told when properies change and when
  51. nodes are added or removed.
  52. @see var, XmlElement
  53. */
  54. class JUCE_API ValueTree
  55. {
  56. public:
  57. //==============================================================================
  58. /** Creates an empty, invalid ValueTree.
  59. A ValueTree that is created with this constructor can't actually be used for anything,
  60. it's just a default 'null' ValueTree that can be returned to indicate some sort of failure.
  61. To create a real one, use the constructor that takes a string.
  62. @see ValueTree::invalid
  63. */
  64. ValueTree() throw();
  65. /** Creates an empty ValueTree with the given type name.
  66. Like an XmlElement, each ValueTree node has a type, which you can access with
  67. getType() and hasType().
  68. */
  69. explicit ValueTree (const String& type);
  70. /** Creates a reference to another ValueTree. */
  71. ValueTree (const ValueTree& other);
  72. /** Makes this object reference another node. */
  73. ValueTree& operator= (const ValueTree& other);
  74. /** Destructor. */
  75. ~ValueTree();
  76. /** Returns true if both this and the other tree node refer to the same underlying structure.
  77. Note that this isn't a value comparison - two independently-created trees which
  78. contain identical data are not considered equal.
  79. */
  80. bool operator== (const ValueTree& other) const;
  81. /** Returns true if this and the other node refer to different underlying structures.
  82. Note that this isn't a value comparison - two independently-created trees which
  83. contain identical data are not considered equal.
  84. */
  85. bool operator!= (const ValueTree& other) const;
  86. //==============================================================================
  87. /** Returns true if this node refers to some valid data.
  88. It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range
  89. call to getChild().
  90. */
  91. bool isValid() const { return object != 0; }
  92. /** Returns a deep copy of this tree and all its sub-nodes. */
  93. ValueTree createCopy() const;
  94. //==============================================================================
  95. /** Returns the type of this node.
  96. The type is specified when the ValueTree is created.
  97. @see hasType
  98. */
  99. const String getType() const;
  100. /** Returns true if the node has this type.
  101. The comparison is case-sensitive.
  102. */
  103. bool hasType (const String& typeName) const;
  104. //==============================================================================
  105. /** Returns the value of a named property.
  106. If no such property has been set, this will return a void variant.
  107. You can also use operator[] to get a property.
  108. @see var, setProperty, hasProperty
  109. */
  110. const var& getProperty (const var::identifier& name) const;
  111. /** Returns the value of a named property, or a user-specified default if the property doesn't exist.
  112. If no such property has been set, this will return the value of defaultReturnValue.
  113. You can also use operator[] and getProperty to get a property.
  114. @see var, getProperty, setProperty, hasProperty
  115. */
  116. const var getProperty (const var::identifier& name, const var& defaultReturnValue) const;
  117. /** Returns the value of a named property.
  118. If no such property has been set, this will return a void variant. This is the same as
  119. calling getProperty().
  120. @see getProperty
  121. */
  122. const var& operator[] (const var::identifier& name) const;
  123. /** Changes a named property of the node.
  124. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  125. so that this change can be undone.
  126. @see var, getProperty, removeProperty
  127. */
  128. void setProperty (const var::identifier& name, const var& newValue, UndoManager* undoManager);
  129. /** Returns true if the node contains a named property. */
  130. bool hasProperty (const var::identifier& name) const;
  131. /** Removes a property from the node.
  132. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  133. so that this change can be undone.
  134. */
  135. void removeProperty (const var::identifier& name, UndoManager* undoManager);
  136. /** Removes all properties from the node.
  137. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  138. so that this change can be undone.
  139. */
  140. void removeAllProperties (UndoManager* undoManager);
  141. /** Returns the total number of properties that the node contains.
  142. @see getProperty.
  143. */
  144. int getNumProperties() const;
  145. /** Returns the identifier of the property with a given index.
  146. @see getNumProperties
  147. */
  148. const var::identifier getPropertyName (int index) const;
  149. /** Returns a Value object that can be used to control and respond to one of the tree's properties.
  150. The Value object will maintain a reference to this tree, and will use the undo manager when
  151. it needs to change the value. Attaching a Value::Listener to the value object will provide
  152. callbacks whenever the property changes.
  153. */
  154. Value getPropertyAsValue (const var::identifier& name, UndoManager* undoManager) const;
  155. //==============================================================================
  156. /** Returns the number of child nodes belonging to this one.
  157. @see getChild
  158. */
  159. int getNumChildren() const;
  160. /** Returns one of this node's child nodes.
  161. If the index is out of range, it'll return an invalid node. (See isValid() to find out
  162. whether a node is valid).
  163. */
  164. ValueTree getChild (int index) const;
  165. /** Looks for a child node with the speficied type name.
  166. If no such node is found, it'll return an invalid node. (See isValid() to find out
  167. whether a node is valid).
  168. */
  169. ValueTree getChildWithName (const String& type) const;
  170. /** Looks for the first child node that has the speficied property value.
  171. This will scan the child nodes in order, until it finds one that has property that matches
  172. the specified value.
  173. If no such node is found, it'll return an invalid node. (See isValid() to find out
  174. whether a node is valid).
  175. */
  176. ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const;
  177. /** Adds a child to this node.
  178. Make sure that the child is removed from any former parent node before calling this, or
  179. you'll hit an assertion.
  180. If the index is < 0 or greater than the current number of child nodes, the new node will
  181. be added at the end of the list.
  182. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  183. so that this change can be undone.
  184. */
  185. void addChild (ValueTree child, int index, UndoManager* undoManager);
  186. /** Removes the specified child from this node's child-list.
  187. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  188. so that this change can be undone.
  189. */
  190. void removeChild (const ValueTree& child, UndoManager* undoManager);
  191. /** Removes a child from this node's child-list.
  192. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  193. so that this change can be undone.
  194. */
  195. void removeChild (int childIndex, UndoManager* undoManager);
  196. /** Removes all child-nodes from this node.
  197. If the undoManager parameter is non-null, its UndoManager::perform() method will be used,
  198. so that this change can be undone.
  199. */
  200. void removeAllChildren (UndoManager* undoManager);
  201. /** Moves one of the children to a different index.
  202. This will move the child to a specified index, shuffling along any intervening
  203. items as required. So for example, if you have a list of { 0, 1, 2, 3, 4, 5 }, then
  204. calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
  205. @param currentIndex the index of the item to be moved. If this isn't a
  206. valid index, then nothing will be done
  207. @param newIndex the index at which you'd like this item to end up. If this
  208. is less than zero, the value will be moved to the end
  209. of the list
  210. @param undoManager the optional UndoManager to use to store this transaction
  211. */
  212. void moveChild (int currentIndex, int newIndex, UndoManager* undoManager);
  213. /** Returns true if this node is anywhere below the specified parent node.
  214. This returns true if the node is a child-of-a-child, as well as a direct child.
  215. */
  216. bool isAChildOf (const ValueTree& possibleParent) const;
  217. /** Returns the index of a child item in this parent.
  218. If the child isn't found, this returns -1.
  219. */
  220. int indexOf (const ValueTree& child) const;
  221. /** Returns the parent node that contains this one.
  222. If the node has no parent, this will return an invalid node. (See isValid() to find out
  223. whether a node is valid).
  224. */
  225. ValueTree getParent() const;
  226. //==============================================================================
  227. /** Creates an XmlElement that holds a complete image of this node and all its children.
  228. If this node is invalid, this may return 0. Otherwise, the XML that is produced can
  229. be used to recreate a similar node by calling fromXml()
  230. @see fromXml
  231. */
  232. XmlElement* createXml() const;
  233. /** Tries to recreate a node from its XML representation.
  234. This isn't designed to cope with random XML data - for a sensible result, it should only
  235. be fed XML that was created by the createXml() method.
  236. */
  237. static ValueTree fromXml (const XmlElement& xml);
  238. //==============================================================================
  239. /** Stores this tree (and all its children) in a binary format.
  240. Once written, the data can be read back with readFromStream().
  241. It's much faster to load/save your tree in binary form than as XML, but
  242. obviously isn't human-readable.
  243. */
  244. void writeToStream (OutputStream& output);
  245. /** Reloads a tree from a stream that was written with writeToStream(). */
  246. static ValueTree readFromStream (InputStream& input);
  247. /** Reloads a tree from a data block that was written with writeToStream(). */
  248. static ValueTree readFromData (const void* data, size_t numBytes);
  249. //==============================================================================
  250. /** Listener class for events that happen to a ValueTree.
  251. To get events from a ValueTree, make your class implement this interface, and use
  252. ValueTree::addListener() and ValueTree::removeListener() to register it.
  253. */
  254. class JUCE_API Listener
  255. {
  256. public:
  257. /** Destructor. */
  258. virtual ~Listener() {}
  259. /** This method is called when a property of this node (or of one of its sub-nodes) has
  260. changed.
  261. The tree parameter indicates which tree has had its property changed, and the property
  262. parameter indicates the property.
  263. Note that when you register a listener to a tree, it will receive this callback for
  264. property changes in that tree, and also for any of its children, (recursively, at any depth).
  265. If your tree has sub-trees but you only want to know about changes to the top level tree,
  266. simply check the tree parameter in this callback to make sure it's the tree you're interested in.
  267. */
  268. virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged,
  269. const var::identifier& property) = 0;
  270. /** This method is called when a child sub-tree is added or removed.
  271. The tree parameter indicates the tree whose child was added or removed.
  272. Note that when you register a listener to a tree, it will receive this callback for
  273. child changes in that tree, and also in any of its children, (recursively, at any depth).
  274. If your tree has sub-trees but you only want to know about changes to the top level tree,
  275. simply check the tree parameter in this callback to make sure it's the tree you're interested in.
  276. */
  277. virtual void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) = 0;
  278. /** This method is called when a tree has been added or removed from a parent node.
  279. This callback happens when the tree to which the listener was registered is added or
  280. removed from a parent. Unlike the other callbacks, it applies only to the tree to which
  281. the listener is registered, and not to any of its children.
  282. */
  283. virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) = 0;
  284. };
  285. /** Adds a listener to receive callbacks when this node is changed.
  286. The listener is added to this specific ValueTree object, and not to the shared
  287. object that it refers to. When this object is deleted, all the listeners will
  288. be lost, even if other references to the same ValueTree still exist. And if you
  289. use the operator= to make this refer to a different ValueTree, any listeners will
  290. begin listening to changes to the new tree instead of the old one.
  291. When you're adding a listener, make sure that you add it to a ValueTree instance that
  292. will last for as long as you need the listener. In general, you'd never want to add a
  293. listener to a local stack-based ValueTree, and would usually add one to a member variable.
  294. @see removeListener
  295. */
  296. void addListener (Listener* listener);
  297. /** Removes a listener that was previously added with addListener(). */
  298. void removeListener (Listener* listener);
  299. //==============================================================================
  300. /** This method uses a comparator object to sort the tree's children into order.
  301. The object provided must have a method of the form:
  302. @code
  303. int compareElements (const ValueTree& first, const ValueTree& second);
  304. @endcode
  305. ..and this method must return:
  306. - a value of < 0 if the first comes before the second
  307. - a value of 0 if the two objects are equivalent
  308. - a value of > 0 if the second comes before the first
  309. To improve performance, the compareElements() method can be declared as static or const.
  310. @param comparator the comparator to use for comparing elements.
  311. @param retainOrderOfEquivalentItems if this is true, then items
  312. which the comparator says are equivalent will be
  313. kept in the order in which they currently appear
  314. in the array. This is slower to perform, but may
  315. be important in some cases. If it's false, a faster
  316. algorithm is used, but equivalent elements may be
  317. rearranged.
  318. */
  319. template <typename ElementComparator>
  320. void sort (ElementComparator& comparator, const bool retainOrderOfEquivalentItems = false)
  321. {
  322. if (object != 0)
  323. {
  324. ComparatorAdapter <ElementComparator> adapter (comparator);
  325. object->children.sort (adapter, retainOrderOfEquivalentItems);
  326. object->sendChildChangeMessage();
  327. }
  328. }
  329. /** An invalid ValueTree that can be used if you need to return one as an error condition, etc.
  330. This invalid object is equivalent to ValueTree created with its default constructor.
  331. */
  332. static const ValueTree invalid;
  333. //==============================================================================
  334. juce_UseDebuggingNewOperator
  335. private:
  336. class SetPropertyAction;
  337. friend class SetPropertyAction;
  338. class AddOrRemoveChildAction;
  339. friend class AddOrRemoveChildAction;
  340. class MoveChildAction;
  341. friend class MoveChildAction;
  342. class JUCE_API SharedObject : public ReferenceCountedObject
  343. {
  344. public:
  345. explicit SharedObject (const String& type);
  346. SharedObject (const SharedObject& other);
  347. ~SharedObject();
  348. const String type;
  349. NamedValueSet properties;
  350. ReferenceCountedArray <SharedObject> children;
  351. SortedSet <ValueTree*> valueTreesWithListeners;
  352. SharedObject* parent;
  353. void sendPropertyChangeMessage (const var::identifier& property);
  354. void sendPropertyChangeMessage (ValueTree& tree, const var::identifier& property);
  355. void sendChildChangeMessage();
  356. void sendChildChangeMessage (ValueTree& tree);
  357. void sendParentChangeMessage();
  358. const var& getProperty (const var::identifier& name) const;
  359. const var getProperty (const var::identifier& name, const var& defaultReturnValue) const;
  360. void setProperty (const var::identifier& name, const var& newValue, UndoManager*);
  361. bool hasProperty (const var::identifier& name) const;
  362. void removeProperty (const var::identifier& name, UndoManager*);
  363. void removeAllProperties (UndoManager*);
  364. bool isAChildOf (const SharedObject* possibleParent) const;
  365. int indexOf (const ValueTree& child) const;
  366. ValueTree getChildWithName (const String& type) const;
  367. ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const;
  368. void addChild (SharedObject* child, int index, UndoManager*);
  369. void removeChild (int childIndex, UndoManager*);
  370. void removeAllChildren (UndoManager*);
  371. void moveChild (int currentIndex, int newIndex, UndoManager*);
  372. XmlElement* createXml() const;
  373. juce_UseDebuggingNewOperator
  374. private:
  375. SharedObject& operator= (const SharedObject&);
  376. };
  377. template <typename ElementComparator>
  378. class ComparatorAdapter
  379. {
  380. public:
  381. ComparatorAdapter (ElementComparator& comparator_) throw() : comparator (comparator_) {}
  382. int compareElements (SharedObject* const first, SharedObject* const second)
  383. {
  384. return comparator.compareElements (ValueTree (first), ValueTree (second));
  385. }
  386. private:
  387. ElementComparator& comparator;
  388. ComparatorAdapter (const ComparatorAdapter&);
  389. ComparatorAdapter& operator= (const ComparatorAdapter&);
  390. };
  391. friend class SharedObject;
  392. typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr;
  393. SharedObjectPtr object;
  394. ListenerList <Listener> listeners;
  395. public:
  396. /** @internal */
  397. explicit ValueTree (SharedObject*); // (can be made private when VC6 support is finally dropped)
  398. };
  399. #endif // __JUCE_VALUETREE_JUCEHEADER__