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.

871 lines
25KB

  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 var::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 var::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& target_,
  130. const int startIndex_, const int endIndex_)
  131. : target (target_),
  132. startIndex (startIndex_),
  133. endIndex (endIndex_)
  134. {
  135. }
  136. ~MoveChildAction() {}
  137. bool perform()
  138. {
  139. target->moveChild (startIndex, endIndex, 0);
  140. return true;
  141. }
  142. bool undo()
  143. {
  144. target->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->target == target && next->child == child)
  155. return new MoveChildAction (target, startIndex, next->endIndex);
  156. return 0;
  157. }
  158. private:
  159. const SharedObjectPtr target, child;
  160. const int startIndex, endIndex;
  161. MoveChildAction (const MoveChildAction&);
  162. MoveChildAction& operator= (const MoveChildAction&);
  163. };
  164. //==============================================================================
  165. ValueTree::SharedObject::SharedObject (const String& 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 var::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 var::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 var::identifier& name) const
  248. {
  249. return properties [name];
  250. }
  251. const var ValueTree::SharedObject::getProperty (const var::identifier& name, const var& defaultReturnValue) const
  252. {
  253. return properties.getWithDefault (name, defaultReturnValue);
  254. }
  255. void ValueTree::SharedObject::setProperty (const var::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 var::identifier& name) const
  277. {
  278. return properties.contains (name);
  279. }
  280. void ValueTree::SharedObject::removeProperty (const var::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 var::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 String& 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::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const
  318. {
  319. for (int i = 0; i < children.size(); ++i)
  320. if (children.getUnchecked(i)->getProperty (propertyName) == propertyValue)
  321. return ValueTree (static_cast <SharedObject*> (children.getUnchecked(i)));
  322. return ValueTree::invalid;
  323. }
  324. bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possibleParent) const
  325. {
  326. const SharedObject* p = parent;
  327. while (p != 0)
  328. {
  329. if (p == possibleParent)
  330. return true;
  331. p = p->parent;
  332. }
  333. return false;
  334. }
  335. int ValueTree::SharedObject::indexOf (const ValueTree& child) const
  336. {
  337. return children.indexOf (child.object);
  338. }
  339. void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager)
  340. {
  341. if (child != 0 && child->parent != this)
  342. {
  343. if (child != this && ! isAChildOf (child))
  344. {
  345. // You should always make sure that a child is removed from its previous parent before
  346. // adding it somewhere else - otherwise, it's ambiguous as to whether a different
  347. // undomanager should be used when removing it from its current parent..
  348. jassert (child->parent == 0);
  349. if (child->parent != 0)
  350. {
  351. jassert (child->parent->children.indexOf (child) >= 0);
  352. child->parent->removeChild (child->parent->children.indexOf (child), undoManager);
  353. }
  354. if (undoManager == 0)
  355. {
  356. children.insert (index, child);
  357. child->parent = this;
  358. sendChildChangeMessage();
  359. child->sendParentChangeMessage();
  360. }
  361. else
  362. {
  363. if (index < 0)
  364. index = children.size();
  365. undoManager->perform (new AddOrRemoveChildAction (this, index, child));
  366. }
  367. }
  368. else
  369. {
  370. // You're attempting to create a recursive loop! A node
  371. // can't be a child of one of its own children!
  372. jassertfalse
  373. }
  374. }
  375. }
  376. void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* const undoManager)
  377. {
  378. const SharedObjectPtr child (children [childIndex]);
  379. if (child != 0)
  380. {
  381. if (undoManager == 0)
  382. {
  383. children.remove (childIndex);
  384. child->parent = 0;
  385. sendChildChangeMessage();
  386. child->sendParentChangeMessage();
  387. }
  388. else
  389. {
  390. undoManager->perform (new AddOrRemoveChildAction (this, childIndex, 0));
  391. }
  392. }
  393. }
  394. void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager)
  395. {
  396. while (children.size() > 0)
  397. removeChild (children.size() - 1, undoManager);
  398. }
  399. void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoManager* undoManager)
  400. {
  401. // The source index must be a valid index!
  402. jassert (((unsigned int) currentIndex) < (unsigned int) children.size());
  403. if (currentIndex != newIndex
  404. && ((unsigned int) currentIndex) < (unsigned int) children.size())
  405. {
  406. if (undoManager == 0)
  407. {
  408. children.move (currentIndex, newIndex);
  409. sendChildChangeMessage();
  410. }
  411. else
  412. {
  413. if (((unsigned int) newIndex) >= (unsigned int) children.size())
  414. newIndex = children.size() - 1;
  415. undoManager->perform (new MoveChildAction (this, currentIndex, newIndex));
  416. }
  417. }
  418. }
  419. //==============================================================================
  420. ValueTree::ValueTree() throw()
  421. : object (0)
  422. {
  423. }
  424. const ValueTree ValueTree::invalid;
  425. ValueTree::ValueTree (const String& type_)
  426. : object (new ValueTree::SharedObject (type_))
  427. {
  428. jassert (type_.isNotEmpty()); // All objects should be given a sensible type name!
  429. }
  430. ValueTree::ValueTree (SharedObject* const object_)
  431. : object (object_)
  432. {
  433. }
  434. ValueTree::ValueTree (const ValueTree& other)
  435. : object (other.object)
  436. {
  437. }
  438. ValueTree& ValueTree::operator= (const ValueTree& other)
  439. {
  440. if (listeners.size() > 0)
  441. {
  442. if (object != 0)
  443. object->valueTreesWithListeners.removeValue (this);
  444. if (other.object != 0)
  445. other.object->valueTreesWithListeners.add (this);
  446. }
  447. object = other.object;
  448. return *this;
  449. }
  450. ValueTree::~ValueTree()
  451. {
  452. if (listeners.size() > 0 && object != 0)
  453. object->valueTreesWithListeners.removeValue (this);
  454. }
  455. bool ValueTree::operator== (const ValueTree& other) const
  456. {
  457. return object == other.object;
  458. }
  459. bool ValueTree::operator!= (const ValueTree& other) const
  460. {
  461. return object != other.object;
  462. }
  463. ValueTree ValueTree::createCopy() const
  464. {
  465. return ValueTree (object != 0 ? new SharedObject (*object) : 0);
  466. }
  467. bool ValueTree::hasType (const String& typeName) const
  468. {
  469. return object != 0 && object->type == typeName;
  470. }
  471. const String ValueTree::getType() const
  472. {
  473. return object != 0 ? object->type : String::empty;
  474. }
  475. ValueTree ValueTree::getParent() const
  476. {
  477. return ValueTree (object != 0 ? object->parent : (SharedObject*) 0);
  478. }
  479. const var& ValueTree::operator[] (const var::identifier& name) const
  480. {
  481. return object == 0 ? var::null : object->getProperty (name);
  482. }
  483. const var& ValueTree::getProperty (const var::identifier& name) const
  484. {
  485. return object == 0 ? var::null : object->getProperty (name);
  486. }
  487. const var ValueTree::getProperty (const var::identifier& name, const var& defaultReturnValue) const
  488. {
  489. return object == 0 ? defaultReturnValue : object->getProperty (name, defaultReturnValue);
  490. }
  491. void ValueTree::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager)
  492. {
  493. jassert (name.name.isNotEmpty());
  494. if (object != 0 && name.name.isNotEmpty())
  495. object->setProperty (name, newValue, undoManager);
  496. }
  497. bool ValueTree::hasProperty (const var::identifier& name) const
  498. {
  499. return object != 0 && object->hasProperty (name);
  500. }
  501. void ValueTree::removeProperty (const var::identifier& name, UndoManager* const undoManager)
  502. {
  503. if (object != 0)
  504. object->removeProperty (name, undoManager);
  505. }
  506. void ValueTree::removeAllProperties (UndoManager* const undoManager)
  507. {
  508. if (object != 0)
  509. object->removeAllProperties (undoManager);
  510. }
  511. int ValueTree::getNumProperties() const
  512. {
  513. return object == 0 ? 0 : object->properties.size();
  514. }
  515. const var::identifier ValueTree::getPropertyName (const int index) const
  516. {
  517. return object == 0 ? var::identifier()
  518. : object->properties.getName (index);
  519. }
  520. //==============================================================================
  521. class ValueTreePropertyValueSource : public Value::ValueSource,
  522. public ValueTree::Listener
  523. {
  524. public:
  525. ValueTreePropertyValueSource (const ValueTree& tree_,
  526. const var::identifier& property_,
  527. UndoManager* const undoManager_)
  528. : tree (tree_),
  529. property (property_),
  530. undoManager (undoManager_)
  531. {
  532. tree.addListener (this);
  533. }
  534. ~ValueTreePropertyValueSource()
  535. {
  536. tree.removeListener (this);
  537. }
  538. const var getValue() const
  539. {
  540. return tree [property];
  541. }
  542. void setValue (const var& newValue)
  543. {
  544. tree.setProperty (property, newValue, undoManager);
  545. }
  546. void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const var::identifier& changedProperty)
  547. {
  548. if (tree == treeWhosePropertyHasChanged && property == changedProperty)
  549. sendChangeMessage (false);
  550. }
  551. void valueTreeChildrenChanged (ValueTree&) {}
  552. void valueTreeParentChanged (ValueTree&) {}
  553. private:
  554. ValueTree tree;
  555. const var::identifier property;
  556. UndoManager* const undoManager;
  557. ValueTreePropertyValueSource& operator= (const ValueTreePropertyValueSource&);
  558. };
  559. Value ValueTree::getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const
  560. {
  561. return Value (new ValueTreePropertyValueSource (*this, name, undoManager));
  562. }
  563. //==============================================================================
  564. int ValueTree::getNumChildren() const
  565. {
  566. return object == 0 ? 0 : object->children.size();
  567. }
  568. ValueTree ValueTree::getChild (int index) const
  569. {
  570. return ValueTree (object != 0 ? (SharedObject*) object->children [index] : (SharedObject*) 0);
  571. }
  572. ValueTree ValueTree::getChildWithName (const String& type) const
  573. {
  574. return object != 0 ? object->getChildWithName (type) : ValueTree::invalid;
  575. }
  576. ValueTree ValueTree::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const
  577. {
  578. return object != 0 ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree::invalid;
  579. }
  580. bool ValueTree::isAChildOf (const ValueTree& possibleParent) const
  581. {
  582. return object != 0 && object->isAChildOf (possibleParent.object);
  583. }
  584. int ValueTree::indexOf (const ValueTree& child) const
  585. {
  586. return object != 0 ? object->indexOf (child) : -1;
  587. }
  588. void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager)
  589. {
  590. if (object != 0)
  591. object->addChild (child.object, index, undoManager);
  592. }
  593. void ValueTree::removeChild (const int childIndex, UndoManager* const undoManager)
  594. {
  595. if (object != 0)
  596. object->removeChild (childIndex, undoManager);
  597. }
  598. void ValueTree::removeChild (const ValueTree& child, UndoManager* const undoManager)
  599. {
  600. if (object != 0)
  601. object->removeChild (object->children.indexOf (child.object), undoManager);
  602. }
  603. void ValueTree::removeAllChildren (UndoManager* const undoManager)
  604. {
  605. if (object != 0)
  606. object->removeAllChildren (undoManager);
  607. }
  608. void ValueTree::moveChild (int currentIndex, int newIndex, UndoManager* undoManager)
  609. {
  610. if (object != 0)
  611. object->moveChild (currentIndex, newIndex, undoManager);
  612. }
  613. //==============================================================================
  614. void ValueTree::addListener (Listener* listener)
  615. {
  616. if (listener != 0)
  617. {
  618. if (listeners.size() == 0 && object != 0)
  619. object->valueTreesWithListeners.add (this);
  620. listeners.add (listener);
  621. }
  622. }
  623. void ValueTree::removeListener (Listener* listener)
  624. {
  625. listeners.remove (listener);
  626. if (listeners.size() == 0 && object != 0)
  627. object->valueTreesWithListeners.removeValue (this);
  628. }
  629. //==============================================================================
  630. XmlElement* ValueTree::SharedObject::createXml() const
  631. {
  632. XmlElement* xml = new XmlElement (type);
  633. int i;
  634. for (i = 0; i < properties.size(); ++i)
  635. {
  636. var::identifier name (properties.getName(i));
  637. const var& v = properties [name];
  638. jassert (! v.isObject()); // DynamicObjects can't be stored as XML!
  639. xml->setAttribute (name.name, v.toString());
  640. }
  641. for (i = 0; i < children.size(); ++i)
  642. xml->addChildElement (children.getUnchecked(i)->createXml());
  643. return xml;
  644. }
  645. XmlElement* ValueTree::createXml() const
  646. {
  647. return object != 0 ? object->createXml() : 0;
  648. }
  649. ValueTree ValueTree::fromXml (const XmlElement& xml)
  650. {
  651. ValueTree v (xml.getTagName());
  652. const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
  653. for (int i = 0; i < numAtts; ++i)
  654. v.setProperty (xml.getAttributeName (i), var (xml.getAttributeValue (i)), 0);
  655. forEachXmlChildElement (xml, e)
  656. {
  657. v.addChild (fromXml (*e), -1, 0);
  658. }
  659. return v;
  660. }
  661. //==============================================================================
  662. void ValueTree::writeToStream (OutputStream& output)
  663. {
  664. output.writeString (getType());
  665. const int numProps = getNumProperties();
  666. output.writeCompressedInt (numProps);
  667. int i;
  668. for (i = 0; i < numProps; ++i)
  669. {
  670. const var::identifier name (getPropertyName(i));
  671. output.writeString (name.name);
  672. getProperty(name).writeToStream (output);
  673. }
  674. const int numChildren = getNumChildren();
  675. output.writeCompressedInt (numChildren);
  676. for (i = 0; i < numChildren; ++i)
  677. getChild (i).writeToStream (output);
  678. }
  679. ValueTree ValueTree::readFromStream (InputStream& input)
  680. {
  681. const String type (input.readString());
  682. if (type.isEmpty())
  683. return ValueTree::invalid;
  684. ValueTree v (type);
  685. const int numProps = input.readCompressedInt();
  686. if (numProps < 0)
  687. {
  688. jassertfalse // trying to read corrupted data!
  689. return v;
  690. }
  691. int i;
  692. for (i = 0; i < numProps; ++i)
  693. {
  694. const String name (input.readString());
  695. jassert (name.isNotEmpty());
  696. const var value (var::readFromStream (input));
  697. v.setProperty (name, value, 0);
  698. }
  699. const int numChildren = input.readCompressedInt();
  700. for (i = 0; i < numChildren; ++i)
  701. v.addChild (readFromStream (input), -1, 0);
  702. return v;
  703. }
  704. ValueTree ValueTree::readFromData (const void* const data, const size_t numBytes)
  705. {
  706. MemoryInputStream in (data, numBytes, false);
  707. return readFromStream (in);
  708. }
  709. END_JUCE_NAMESPACE