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.

953 lines
28KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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. #include "../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_ValueTree.h"
  21. #include "../io/streams/juce_MemoryInputStream.h"
  22. //==============================================================================
  23. class ValueTree::SetPropertyAction : public UndoableAction
  24. {
  25. public:
  26. SetPropertyAction (const SharedObjectPtr& target_, const Identifier& name_,
  27. const var& newValue_, const var& oldValue_,
  28. const bool isAddingNewProperty_, const bool isDeletingProperty_)
  29. : target (target_), name (name_), newValue (newValue_), oldValue (oldValue_),
  30. isAddingNewProperty (isAddingNewProperty_), isDeletingProperty (isDeletingProperty_)
  31. {
  32. }
  33. bool perform()
  34. {
  35. jassert (! (isAddingNewProperty && target->hasProperty (name)));
  36. if (isDeletingProperty)
  37. target->removeProperty (name, nullptr);
  38. else
  39. target->setProperty (name, newValue, nullptr);
  40. return true;
  41. }
  42. bool undo()
  43. {
  44. if (isAddingNewProperty)
  45. target->removeProperty (name, nullptr);
  46. else
  47. target->setProperty (name, oldValue, nullptr);
  48. return true;
  49. }
  50. int getSizeInUnits()
  51. {
  52. return (int) sizeof (*this); //xxx should be more accurate
  53. }
  54. UndoableAction* createCoalescedAction (UndoableAction* nextAction)
  55. {
  56. if (! (isAddingNewProperty || isDeletingProperty))
  57. {
  58. SetPropertyAction* next = dynamic_cast <SetPropertyAction*> (nextAction);
  59. if (next != nullptr && next->target == target && next->name == name
  60. && ! (next->isAddingNewProperty || next->isDeletingProperty))
  61. {
  62. return new SetPropertyAction (target, name, next->newValue, oldValue, false, false);
  63. }
  64. }
  65. return nullptr;
  66. }
  67. private:
  68. const SharedObjectPtr target;
  69. const Identifier name;
  70. const var newValue;
  71. var oldValue;
  72. const bool isAddingNewProperty : 1, isDeletingProperty : 1;
  73. JUCE_DECLARE_NON_COPYABLE (SetPropertyAction);
  74. };
  75. //==============================================================================
  76. class ValueTree::AddOrRemoveChildAction : public UndoableAction
  77. {
  78. public:
  79. AddOrRemoveChildAction (const SharedObjectPtr& target_, const int childIndex_,
  80. const SharedObjectPtr& newChild_)
  81. : target (target_),
  82. child (newChild_ != nullptr ? newChild_ : target_->children [childIndex_]),
  83. childIndex (childIndex_),
  84. isDeleting (newChild_ == nullptr)
  85. {
  86. jassert (child != nullptr);
  87. }
  88. bool perform()
  89. {
  90. if (isDeleting)
  91. target->removeChild (childIndex, nullptr);
  92. else
  93. target->addChild (child, childIndex, nullptr);
  94. return true;
  95. }
  96. bool undo()
  97. {
  98. if (isDeleting)
  99. {
  100. target->addChild (child, childIndex, nullptr);
  101. }
  102. else
  103. {
  104. // If you hit this, it seems that your object's state is getting confused - probably
  105. // because you've interleaved some undoable and non-undoable operations?
  106. jassert (childIndex < target->children.size());
  107. target->removeChild (childIndex, nullptr);
  108. }
  109. return true;
  110. }
  111. int getSizeInUnits()
  112. {
  113. return (int) sizeof (*this); //xxx should be more accurate
  114. }
  115. private:
  116. const SharedObjectPtr target, child;
  117. const int childIndex;
  118. const bool isDeleting;
  119. JUCE_DECLARE_NON_COPYABLE (AddOrRemoveChildAction);
  120. };
  121. //==============================================================================
  122. class ValueTree::MoveChildAction : public UndoableAction
  123. {
  124. public:
  125. MoveChildAction (const SharedObjectPtr& parent_,
  126. const int startIndex_, const int endIndex_)
  127. : parent (parent_),
  128. startIndex (startIndex_),
  129. endIndex (endIndex_)
  130. {
  131. }
  132. bool perform()
  133. {
  134. parent->moveChild (startIndex, endIndex, nullptr);
  135. return true;
  136. }
  137. bool undo()
  138. {
  139. parent->moveChild (endIndex, startIndex, nullptr);
  140. return true;
  141. }
  142. int getSizeInUnits()
  143. {
  144. return (int) sizeof (*this); //xxx should be more accurate
  145. }
  146. UndoableAction* createCoalescedAction (UndoableAction* nextAction)
  147. {
  148. MoveChildAction* next = dynamic_cast <MoveChildAction*> (nextAction);
  149. if (next != nullptr && next->parent == parent && next->startIndex == endIndex)
  150. return new MoveChildAction (parent, startIndex, next->endIndex);
  151. return nullptr;
  152. }
  153. private:
  154. const SharedObjectPtr parent;
  155. const int startIndex, endIndex;
  156. JUCE_DECLARE_NON_COPYABLE (MoveChildAction);
  157. };
  158. //==============================================================================
  159. ValueTree::SharedObject::SharedObject (const Identifier& type_)
  160. : type (type_), parent (nullptr)
  161. {
  162. }
  163. ValueTree::SharedObject::SharedObject (const SharedObject& other)
  164. : type (other.type), properties (other.properties), parent (nullptr)
  165. {
  166. for (int i = 0; i < other.children.size(); ++i)
  167. {
  168. SharedObject* const child = new SharedObject (*other.children.getUnchecked(i));
  169. child->parent = this;
  170. children.add (child);
  171. }
  172. }
  173. ValueTree::SharedObject::~SharedObject()
  174. {
  175. jassert (parent == nullptr); // this should never happen unless something isn't obeying the ref-counting!
  176. for (int i = children.size(); --i >= 0;)
  177. {
  178. const SharedObjectPtr c (children.getUnchecked(i));
  179. c->parent = nullptr;
  180. children.remove (i);
  181. c->sendParentChangeMessage();
  182. }
  183. }
  184. //==============================================================================
  185. void ValueTree::SharedObject::sendPropertyChangeMessage (ValueTree& tree, const Identifier& property)
  186. {
  187. for (int i = valueTreesWithListeners.size(); --i >= 0;)
  188. {
  189. ValueTree* const v = valueTreesWithListeners[i];
  190. if (v != nullptr)
  191. v->listeners.call (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
  192. }
  193. }
  194. void ValueTree::SharedObject::sendPropertyChangeMessage (const Identifier& property)
  195. {
  196. ValueTree tree (this);
  197. for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
  198. t->sendPropertyChangeMessage (tree, property);
  199. }
  200. void ValueTree::SharedObject::sendChildAddedMessage (ValueTree& tree, ValueTree& child)
  201. {
  202. for (int i = valueTreesWithListeners.size(); --i >= 0;)
  203. {
  204. ValueTree* const v = valueTreesWithListeners[i];
  205. if (v != nullptr)
  206. v->listeners.call (&ValueTree::Listener::valueTreeChildAdded, tree, child);
  207. }
  208. }
  209. void ValueTree::SharedObject::sendChildAddedMessage (ValueTree child)
  210. {
  211. ValueTree tree (this);
  212. for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
  213. t->sendChildAddedMessage (tree, child);
  214. }
  215. void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree& tree, ValueTree& child)
  216. {
  217. for (int i = valueTreesWithListeners.size(); --i >= 0;)
  218. {
  219. ValueTree* const v = valueTreesWithListeners[i];
  220. if (v != nullptr)
  221. v->listeners.call (&ValueTree::Listener::valueTreeChildRemoved, tree, child);
  222. }
  223. }
  224. void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree child)
  225. {
  226. ValueTree tree (this);
  227. for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
  228. t->sendChildRemovedMessage (tree, child);
  229. }
  230. void ValueTree::SharedObject::sendChildOrderChangedMessage (ValueTree& tree)
  231. {
  232. for (int i = valueTreesWithListeners.size(); --i >= 0;)
  233. {
  234. ValueTree* const v = valueTreesWithListeners[i];
  235. if (v != nullptr)
  236. v->listeners.call (&ValueTree::Listener::valueTreeChildOrderChanged, tree);
  237. }
  238. }
  239. void ValueTree::SharedObject::sendChildOrderChangedMessage()
  240. {
  241. ValueTree tree (this);
  242. for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
  243. t->sendChildOrderChangedMessage (tree);
  244. }
  245. void ValueTree::SharedObject::sendParentChangeMessage()
  246. {
  247. ValueTree tree (this);
  248. int i;
  249. for (i = children.size(); --i >= 0;)
  250. {
  251. SharedObject* const t = children[i];
  252. if (t != nullptr)
  253. t->sendParentChangeMessage();
  254. }
  255. for (i = valueTreesWithListeners.size(); --i >= 0;)
  256. {
  257. ValueTree* const v = valueTreesWithListeners[i];
  258. if (v != nullptr)
  259. v->listeners.call (&ValueTree::Listener::valueTreeParentChanged, tree);
  260. }
  261. }
  262. //==============================================================================
  263. const var& ValueTree::SharedObject::getProperty (const Identifier& name) const
  264. {
  265. return properties [name];
  266. }
  267. const var ValueTree::SharedObject::getProperty (const Identifier& name, const var& defaultReturnValue) const
  268. {
  269. return properties.getWithDefault (name, defaultReturnValue);
  270. }
  271. void ValueTree::SharedObject::setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager)
  272. {
  273. if (undoManager == nullptr)
  274. {
  275. if (properties.set (name, newValue))
  276. sendPropertyChangeMessage (name);
  277. }
  278. else
  279. {
  280. var* const existingValue = properties.getVarPointer (name);
  281. if (existingValue != nullptr)
  282. {
  283. if (*existingValue != newValue)
  284. undoManager->perform (new SetPropertyAction (this, name, newValue, properties [name], false, false));
  285. }
  286. else
  287. {
  288. undoManager->perform (new SetPropertyAction (this, name, newValue, var::null, true, false));
  289. }
  290. }
  291. }
  292. bool ValueTree::SharedObject::hasProperty (const Identifier& name) const
  293. {
  294. return properties.contains (name);
  295. }
  296. void ValueTree::SharedObject::removeProperty (const Identifier& name, UndoManager* const undoManager)
  297. {
  298. if (undoManager == nullptr)
  299. {
  300. if (properties.remove (name))
  301. sendPropertyChangeMessage (name);
  302. }
  303. else
  304. {
  305. if (properties.contains (name))
  306. undoManager->perform (new SetPropertyAction (this, name, var::null, properties [name], false, true));
  307. }
  308. }
  309. void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManager)
  310. {
  311. if (undoManager == nullptr)
  312. {
  313. while (properties.size() > 0)
  314. {
  315. const Identifier name (properties.getName (properties.size() - 1));
  316. properties.remove (name);
  317. sendPropertyChangeMessage (name);
  318. }
  319. }
  320. else
  321. {
  322. for (int i = properties.size(); --i >= 0;)
  323. undoManager->perform (new SetPropertyAction (this, properties.getName(i), var::null, properties.getValueAt(i), false, true));
  324. }
  325. }
  326. ValueTree ValueTree::SharedObject::getChildWithName (const Identifier& typeToMatch) const
  327. {
  328. for (int i = 0; i < children.size(); ++i)
  329. if (children.getUnchecked(i)->type == typeToMatch)
  330. return ValueTree (children.getUnchecked(i).getObject());
  331. return ValueTree::invalid;
  332. }
  333. ValueTree ValueTree::SharedObject::getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager)
  334. {
  335. for (int i = 0; i < children.size(); ++i)
  336. if (children.getUnchecked(i)->type == typeToMatch)
  337. return ValueTree (children.getUnchecked(i).getObject());
  338. SharedObject* const newObject = new SharedObject (typeToMatch);
  339. addChild (newObject, -1, undoManager);
  340. return ValueTree (newObject);
  341. }
  342. ValueTree ValueTree::SharedObject::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
  343. {
  344. for (int i = 0; i < children.size(); ++i)
  345. if (children.getUnchecked(i)->getProperty (propertyName) == propertyValue)
  346. return ValueTree (children.getUnchecked(i).getObject());
  347. return ValueTree::invalid;
  348. }
  349. bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possibleParent) const
  350. {
  351. const SharedObject* p = parent;
  352. while (p != nullptr)
  353. {
  354. if (p == possibleParent)
  355. return true;
  356. p = p->parent;
  357. }
  358. return false;
  359. }
  360. int ValueTree::SharedObject::indexOf (const ValueTree& child) const
  361. {
  362. return children.indexOf (child.object);
  363. }
  364. void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager)
  365. {
  366. if (child != nullptr && child->parent != this)
  367. {
  368. if (child != this && ! isAChildOf (child))
  369. {
  370. // You should always make sure that a child is removed from its previous parent before
  371. // adding it somewhere else - otherwise, it's ambiguous as to whether a different
  372. // undomanager should be used when removing it from its current parent..
  373. jassert (child->parent == nullptr);
  374. if (child->parent != nullptr)
  375. {
  376. jassert (child->parent->children.indexOf (child) >= 0);
  377. child->parent->removeChild (child->parent->children.indexOf (child), undoManager);
  378. }
  379. if (undoManager == nullptr)
  380. {
  381. children.insert (index, child);
  382. child->parent = this;
  383. sendChildAddedMessage (ValueTree (child));
  384. child->sendParentChangeMessage();
  385. }
  386. else
  387. {
  388. if (index < 0)
  389. index = children.size();
  390. undoManager->perform (new AddOrRemoveChildAction (this, index, child));
  391. }
  392. }
  393. else
  394. {
  395. // You're attempting to create a recursive loop! A node
  396. // can't be a child of one of its own children!
  397. jassertfalse;
  398. }
  399. }
  400. }
  401. void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* const undoManager)
  402. {
  403. const SharedObjectPtr child (children [childIndex]);
  404. if (child != nullptr)
  405. {
  406. if (undoManager == nullptr)
  407. {
  408. children.remove (childIndex);
  409. child->parent = nullptr;
  410. sendChildRemovedMessage (ValueTree (child));
  411. child->sendParentChangeMessage();
  412. }
  413. else
  414. {
  415. undoManager->perform (new AddOrRemoveChildAction (this, childIndex, nullptr));
  416. }
  417. }
  418. }
  419. void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager)
  420. {
  421. while (children.size() > 0)
  422. removeChild (children.size() - 1, undoManager);
  423. }
  424. void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoManager* undoManager)
  425. {
  426. // The source index must be a valid index!
  427. jassert (isPositiveAndBelow (currentIndex, children.size()));
  428. if (currentIndex != newIndex
  429. && isPositiveAndBelow (currentIndex, children.size()))
  430. {
  431. if (undoManager == nullptr)
  432. {
  433. children.move (currentIndex, newIndex);
  434. sendChildOrderChangedMessage();
  435. }
  436. else
  437. {
  438. if (! isPositiveAndBelow (newIndex, children.size()))
  439. newIndex = children.size() - 1;
  440. undoManager->perform (new MoveChildAction (this, currentIndex, newIndex));
  441. }
  442. }
  443. }
  444. void ValueTree::SharedObject::reorderChildren (const ReferenceCountedArray <SharedObject>& newOrder, UndoManager* undoManager)
  445. {
  446. jassert (newOrder.size() == children.size());
  447. if (undoManager == nullptr)
  448. {
  449. children = newOrder;
  450. sendChildOrderChangedMessage();
  451. }
  452. else
  453. {
  454. for (int i = 0; i < children.size(); ++i)
  455. {
  456. const SharedObjectPtr child (newOrder.getUnchecked(i));
  457. if (children.getUnchecked(i) != child)
  458. {
  459. const int oldIndex = children.indexOf (child);
  460. jassert (oldIndex >= 0);
  461. moveChild (oldIndex, i, undoManager);
  462. }
  463. }
  464. }
  465. }
  466. bool ValueTree::SharedObject::isEquivalentTo (const SharedObject& other) const
  467. {
  468. if (type != other.type
  469. || properties.size() != other.properties.size()
  470. || children.size() != other.children.size()
  471. || properties != other.properties)
  472. return false;
  473. for (int i = 0; i < children.size(); ++i)
  474. if (! children.getUnchecked(i)->isEquivalentTo (*other.children.getUnchecked(i)))
  475. return false;
  476. return true;
  477. }
  478. //==============================================================================
  479. ValueTree::ValueTree() noexcept
  480. {
  481. }
  482. const ValueTree ValueTree::invalid;
  483. ValueTree::ValueTree (const Identifier& type_)
  484. : object (new ValueTree::SharedObject (type_))
  485. {
  486. jassert (type_.toString().isNotEmpty()); // All objects should be given a sensible type name!
  487. }
  488. ValueTree::ValueTree (SharedObject* const object_)
  489. : object (object_)
  490. {
  491. }
  492. ValueTree::ValueTree (const ValueTree& other)
  493. : object (other.object)
  494. {
  495. }
  496. ValueTree& ValueTree::operator= (const ValueTree& other)
  497. {
  498. if (listeners.size() > 0)
  499. {
  500. if (object != nullptr)
  501. object->valueTreesWithListeners.removeValue (this);
  502. if (other.object != nullptr)
  503. other.object->valueTreesWithListeners.add (this);
  504. }
  505. object = other.object;
  506. return *this;
  507. }
  508. ValueTree::~ValueTree()
  509. {
  510. if (listeners.size() > 0 && object != nullptr)
  511. object->valueTreesWithListeners.removeValue (this);
  512. }
  513. bool ValueTree::operator== (const ValueTree& other) const noexcept
  514. {
  515. return object == other.object;
  516. }
  517. bool ValueTree::operator!= (const ValueTree& other) const noexcept
  518. {
  519. return object != other.object;
  520. }
  521. bool ValueTree::isEquivalentTo (const ValueTree& other) const
  522. {
  523. return object == other.object
  524. || (object != nullptr && other.object != nullptr && object->isEquivalentTo (*other.object));
  525. }
  526. ValueTree ValueTree::createCopy() const
  527. {
  528. return ValueTree (object != nullptr ? new SharedObject (*object) : nullptr);
  529. }
  530. bool ValueTree::hasType (const Identifier& typeName) const
  531. {
  532. return object != nullptr && object->type == typeName;
  533. }
  534. const Identifier ValueTree::getType() const
  535. {
  536. return object != nullptr ? object->type : Identifier();
  537. }
  538. ValueTree ValueTree::getParent() const
  539. {
  540. return ValueTree (object != nullptr ? object->parent : (SharedObject*) nullptr);
  541. }
  542. ValueTree ValueTree::getSibling (const int delta) const
  543. {
  544. if (object == nullptr || object->parent == nullptr)
  545. return invalid;
  546. const int index = object->parent->indexOf (*this) + delta;
  547. return ValueTree (object->parent->children [index].getObject());
  548. }
  549. const var& ValueTree::operator[] (const Identifier& name) const
  550. {
  551. return object == nullptr ? var::null : object->getProperty (name);
  552. }
  553. const var& ValueTree::getProperty (const Identifier& name) const
  554. {
  555. return object == nullptr ? var::null : object->getProperty (name);
  556. }
  557. const var ValueTree::getProperty (const Identifier& name, const var& defaultReturnValue) const
  558. {
  559. return object == nullptr ? defaultReturnValue : object->getProperty (name, defaultReturnValue);
  560. }
  561. void ValueTree::setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager)
  562. {
  563. jassert (name.toString().isNotEmpty());
  564. if (object != nullptr && name.toString().isNotEmpty())
  565. object->setProperty (name, newValue, undoManager);
  566. }
  567. bool ValueTree::hasProperty (const Identifier& name) const
  568. {
  569. return object != nullptr && object->hasProperty (name);
  570. }
  571. void ValueTree::removeProperty (const Identifier& name, UndoManager* const undoManager)
  572. {
  573. if (object != nullptr)
  574. object->removeProperty (name, undoManager);
  575. }
  576. void ValueTree::removeAllProperties (UndoManager* const undoManager)
  577. {
  578. if (object != nullptr)
  579. object->removeAllProperties (undoManager);
  580. }
  581. int ValueTree::getNumProperties() const
  582. {
  583. return object == nullptr ? 0 : object->properties.size();
  584. }
  585. const Identifier ValueTree::getPropertyName (const int index) const
  586. {
  587. return object == nullptr ? Identifier()
  588. : object->properties.getName (index);
  589. }
  590. //==============================================================================
  591. class ValueTreePropertyValueSource : public Value::ValueSource,
  592. public ValueTree::Listener
  593. {
  594. public:
  595. ValueTreePropertyValueSource (const ValueTree& tree_,
  596. const Identifier& property_,
  597. UndoManager* const undoManager_)
  598. : tree (tree_),
  599. property (property_),
  600. undoManager (undoManager_)
  601. {
  602. tree.addListener (this);
  603. }
  604. ~ValueTreePropertyValueSource()
  605. {
  606. tree.removeListener (this);
  607. }
  608. const var getValue() const
  609. {
  610. return tree [property];
  611. }
  612. void setValue (const var& newValue)
  613. {
  614. tree.setProperty (property, newValue, undoManager);
  615. }
  616. void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& changedProperty)
  617. {
  618. if (tree == treeWhosePropertyHasChanged && property == changedProperty)
  619. sendChangeMessage (false);
  620. }
  621. void valueTreeChildAdded (ValueTree&, ValueTree&) {}
  622. void valueTreeChildRemoved (ValueTree&, ValueTree&) {}
  623. void valueTreeChildOrderChanged (ValueTree&) {}
  624. void valueTreeParentChanged (ValueTree&) {}
  625. private:
  626. ValueTree tree;
  627. const Identifier property;
  628. UndoManager* const undoManager;
  629. ValueTreePropertyValueSource& operator= (const ValueTreePropertyValueSource&);
  630. };
  631. Value ValueTree::getPropertyAsValue (const Identifier& name, UndoManager* const undoManager) const
  632. {
  633. return Value (new ValueTreePropertyValueSource (*this, name, undoManager));
  634. }
  635. //==============================================================================
  636. int ValueTree::getNumChildren() const
  637. {
  638. return object == nullptr ? 0 : object->children.size();
  639. }
  640. ValueTree ValueTree::getChild (int index) const
  641. {
  642. return ValueTree (object != nullptr ? (SharedObject*) object->children [index] : (SharedObject*) nullptr);
  643. }
  644. ValueTree ValueTree::getChildWithName (const Identifier& type) const
  645. {
  646. return object != nullptr ? object->getChildWithName (type) : ValueTree::invalid;
  647. }
  648. ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager)
  649. {
  650. return object != nullptr ? object->getOrCreateChildWithName (type, undoManager) : ValueTree::invalid;
  651. }
  652. ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
  653. {
  654. return object != nullptr ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree::invalid;
  655. }
  656. bool ValueTree::isAChildOf (const ValueTree& possibleParent) const
  657. {
  658. return object != nullptr && object->isAChildOf (possibleParent.object);
  659. }
  660. int ValueTree::indexOf (const ValueTree& child) const
  661. {
  662. return object != nullptr ? object->indexOf (child) : -1;
  663. }
  664. void ValueTree::addChild (const ValueTree& child, int index, UndoManager* const undoManager)
  665. {
  666. if (object != nullptr)
  667. object->addChild (child.object, index, undoManager);
  668. }
  669. void ValueTree::removeChild (const int childIndex, UndoManager* const undoManager)
  670. {
  671. if (object != nullptr)
  672. object->removeChild (childIndex, undoManager);
  673. }
  674. void ValueTree::removeChild (const ValueTree& child, UndoManager* const undoManager)
  675. {
  676. if (object != nullptr)
  677. object->removeChild (object->children.indexOf (child.object), undoManager);
  678. }
  679. void ValueTree::removeAllChildren (UndoManager* const undoManager)
  680. {
  681. if (object != nullptr)
  682. object->removeAllChildren (undoManager);
  683. }
  684. void ValueTree::moveChild (int currentIndex, int newIndex, UndoManager* undoManager)
  685. {
  686. if (object != nullptr)
  687. object->moveChild (currentIndex, newIndex, undoManager);
  688. }
  689. //==============================================================================
  690. void ValueTree::addListener (Listener* listener)
  691. {
  692. if (listener != nullptr)
  693. {
  694. if (listeners.size() == 0 && object != nullptr)
  695. object->valueTreesWithListeners.add (this);
  696. listeners.add (listener);
  697. }
  698. }
  699. void ValueTree::removeListener (Listener* listener)
  700. {
  701. listeners.remove (listener);
  702. if (listeners.size() == 0 && object != nullptr)
  703. object->valueTreesWithListeners.removeValue (this);
  704. }
  705. //==============================================================================
  706. XmlElement* ValueTree::SharedObject::createXml() const
  707. {
  708. XmlElement* const xml = new XmlElement (type.toString());
  709. properties.copyToXmlAttributes (*xml);
  710. for (int i = 0; i < children.size(); ++i)
  711. xml->addChildElement (children.getUnchecked(i)->createXml());
  712. return xml;
  713. }
  714. XmlElement* ValueTree::createXml() const
  715. {
  716. return object != nullptr ? object->createXml() : nullptr;
  717. }
  718. ValueTree ValueTree::fromXml (const XmlElement& xml)
  719. {
  720. ValueTree v (xml.getTagName());
  721. v.object->properties.setFromXmlAttributes (xml);
  722. forEachXmlChildElement (xml, e)
  723. v.addChild (fromXml (*e), -1, nullptr);
  724. return v;
  725. }
  726. //==============================================================================
  727. void ValueTree::writeToStream (OutputStream& output)
  728. {
  729. output.writeString (getType().toString());
  730. const int numProps = getNumProperties();
  731. output.writeCompressedInt (numProps);
  732. int i;
  733. for (i = 0; i < numProps; ++i)
  734. {
  735. const Identifier name (getPropertyName(i));
  736. output.writeString (name.toString());
  737. getProperty(name).writeToStream (output);
  738. }
  739. const int numChildren = getNumChildren();
  740. output.writeCompressedInt (numChildren);
  741. for (i = 0; i < numChildren; ++i)
  742. getChild (i).writeToStream (output);
  743. }
  744. ValueTree ValueTree::readFromStream (InputStream& input)
  745. {
  746. const String type (input.readString());
  747. if (type.isEmpty())
  748. return ValueTree::invalid;
  749. ValueTree v (type);
  750. const int numProps = input.readCompressedInt();
  751. if (numProps < 0)
  752. {
  753. jassertfalse; // trying to read corrupted data!
  754. return v;
  755. }
  756. int i;
  757. for (i = 0; i < numProps; ++i)
  758. {
  759. const String name (input.readString());
  760. jassert (name.isNotEmpty());
  761. const var value (var::readFromStream (input));
  762. v.object->properties.set (name, value);
  763. }
  764. const int numChildren = input.readCompressedInt();
  765. for (i = 0; i < numChildren; ++i)
  766. {
  767. ValueTree child (readFromStream (input));
  768. v.object->children.add (child.object);
  769. child.object->parent = v.object;
  770. }
  771. return v;
  772. }
  773. ValueTree ValueTree::readFromData (const void* const data, const size_t numBytes)
  774. {
  775. MemoryInputStream in (data, numBytes, false);
  776. return readFromStream (in);
  777. }
  778. END_JUCE_NAMESPACE