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.

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