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.

919 lines
26KB

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