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.

744 lines
21KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. //==============================================================================
  22. class ValueTreeSetPropertyAction : public UndoableAction
  23. {
  24. public:
  25. ValueTreeSetPropertyAction (const ValueTree::SharedObjectPtr& target_, const var::identifier& name_,
  26. const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_)
  27. : target (target_), name (name_), newValue (newValue_),
  28. isAddingNewProperty (isAddingNewProperty_),
  29. isDeletingProperty (isDeletingProperty_)
  30. {
  31. if (! isAddingNewProperty)
  32. oldValue = target_->getProperty (name_);
  33. }
  34. ~ValueTreeSetPropertyAction() {}
  35. bool perform()
  36. {
  37. jassert (! (isAddingNewProperty && target->hasProperty (name)));
  38. if (isDeletingProperty)
  39. target->removeProperty (name, 0);
  40. else
  41. target->setProperty (name, newValue, 0);
  42. return true;
  43. }
  44. bool undo()
  45. {
  46. if (isAddingNewProperty)
  47. target->removeProperty (name, 0);
  48. else
  49. target->setProperty (name, oldValue, 0);
  50. return true;
  51. }
  52. int getSizeInUnits()
  53. {
  54. return (int) sizeof (*this); //xxx should be more accurate
  55. }
  56. private:
  57. const ValueTree::SharedObjectPtr target;
  58. const var::identifier name;
  59. const var newValue;
  60. var oldValue;
  61. const bool isAddingNewProperty, isDeletingProperty;
  62. ValueTreeSetPropertyAction (const ValueTreeSetPropertyAction&);
  63. ValueTreeSetPropertyAction& operator= (const ValueTreeSetPropertyAction&);
  64. };
  65. //==============================================================================
  66. class ValueTreeChildChangeAction : public UndoableAction
  67. {
  68. public:
  69. ValueTreeChildChangeAction (const ValueTree::SharedObjectPtr& target_, const int childIndex_,
  70. const ValueTree::SharedObjectPtr& newChild_)
  71. : target (target_),
  72. child (newChild_ != 0 ? newChild_ : target_->children [childIndex_]),
  73. childIndex (childIndex_),
  74. isDeleting (newChild_ == 0)
  75. {
  76. jassert (child != 0);
  77. }
  78. ~ValueTreeChildChangeAction() {}
  79. bool perform()
  80. {
  81. if (isDeleting)
  82. target->removeChild (childIndex, 0);
  83. else
  84. target->addChild (child, childIndex, 0);
  85. return true;
  86. }
  87. bool undo()
  88. {
  89. if (isDeleting)
  90. target->addChild (child, childIndex, 0);
  91. else
  92. target->removeChild (childIndex, 0);
  93. return true;
  94. }
  95. int getSizeInUnits()
  96. {
  97. return (int) sizeof (*this); //xxx should be more accurate
  98. }
  99. private:
  100. const ValueTree::SharedObjectPtr target, child;
  101. const int childIndex;
  102. const bool isDeleting;
  103. ValueTreeChildChangeAction (const ValueTreeChildChangeAction&);
  104. ValueTreeChildChangeAction& operator= (const ValueTreeChildChangeAction&);
  105. };
  106. //==============================================================================
  107. ValueTree::SharedObject::SharedObject (const String& type_)
  108. : type (type_), parent (0)
  109. {
  110. }
  111. ValueTree::SharedObject::SharedObject (const SharedObject& other)
  112. : type (other.type), properties (other.properties), parent (0)
  113. {
  114. for (int i = 0; i < other.children.size(); ++i)
  115. children.add (new SharedObject (*other.children.getUnchecked(i)));
  116. }
  117. ValueTree::SharedObject::~SharedObject()
  118. {
  119. jassert (parent == 0); // this should never happen unless something isn't obeying the ref-counting!
  120. for (int i = children.size(); --i >= 0;)
  121. {
  122. const SharedObjectPtr c (children.getUnchecked(i));
  123. c->parent = 0;
  124. children.remove (i);
  125. c->sendParentChangeMessage();
  126. }
  127. }
  128. //==============================================================================
  129. void ValueTree::SharedObject::sendPropertyChangeMessage (ValueTree& tree, const var::identifier& property)
  130. {
  131. for (int i = valueTreesWithListeners.size(); --i >= 0;)
  132. {
  133. ValueTree* const v = valueTreesWithListeners[i];
  134. if (v != 0)
  135. v->listeners.call (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
  136. }
  137. }
  138. void ValueTree::SharedObject::sendPropertyChangeMessage (const var::identifier& property)
  139. {
  140. ValueTree tree (this);
  141. ValueTree::SharedObject* t = this;
  142. while (t != 0)
  143. {
  144. t->sendPropertyChangeMessage (tree, property);
  145. t = t->parent;
  146. }
  147. }
  148. void ValueTree::SharedObject::sendChildChangeMessage (ValueTree& tree)
  149. {
  150. for (int i = valueTreesWithListeners.size(); --i >= 0;)
  151. {
  152. ValueTree* const v = valueTreesWithListeners[i];
  153. if (v != 0)
  154. v->listeners.call (&ValueTree::Listener::valueTreeChildrenChanged, tree);
  155. }
  156. }
  157. void ValueTree::SharedObject::sendChildChangeMessage()
  158. {
  159. ValueTree tree (this);
  160. ValueTree::SharedObject* t = this;
  161. while (t != 0)
  162. {
  163. t->sendChildChangeMessage (tree);
  164. t = t->parent;
  165. }
  166. }
  167. void ValueTree::SharedObject::sendParentChangeMessage()
  168. {
  169. ValueTree tree (this);
  170. int i;
  171. for (i = children.size(); --i >= 0;)
  172. {
  173. SharedObject* const t = children[i];
  174. if (t != 0)
  175. t->sendParentChangeMessage();
  176. }
  177. for (i = valueTreesWithListeners.size(); --i >= 0;)
  178. {
  179. ValueTree* const v = valueTreesWithListeners[i];
  180. if (v != 0)
  181. v->listeners.call (&ValueTree::Listener::valueTreeParentChanged, tree);
  182. }
  183. }
  184. //==============================================================================
  185. const var& ValueTree::SharedObject::getProperty (const var::identifier& name) const
  186. {
  187. return properties [name];
  188. }
  189. const var ValueTree::SharedObject::getProperty (const var::identifier& name, const var& defaultReturnValue) const
  190. {
  191. return properties.getWithDefault (name, defaultReturnValue);
  192. }
  193. void ValueTree::SharedObject::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager)
  194. {
  195. if (undoManager == 0)
  196. {
  197. if (properties.set (name, newValue))
  198. sendPropertyChangeMessage (name);
  199. }
  200. else
  201. {
  202. var* const existingValue = properties.getItem (name);
  203. if (existingValue != 0)
  204. {
  205. if (*existingValue != newValue)
  206. undoManager->perform (new ValueTreeSetPropertyAction (this, name, newValue, false, false));
  207. }
  208. else
  209. {
  210. undoManager->perform (new ValueTreeSetPropertyAction (this, name, newValue, true, false));
  211. }
  212. }
  213. }
  214. bool ValueTree::SharedObject::hasProperty (const var::identifier& name) const
  215. {
  216. return properties.contains (name);
  217. }
  218. void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoManager* const undoManager)
  219. {
  220. if (undoManager == 0)
  221. {
  222. if (properties.remove (name))
  223. sendPropertyChangeMessage (name);
  224. }
  225. else
  226. {
  227. if (properties.contains (name))
  228. undoManager->perform (new ValueTreeSetPropertyAction (this, name, var::null, false, true));
  229. }
  230. }
  231. void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManager)
  232. {
  233. if (undoManager == 0)
  234. {
  235. while (properties.size() > 0)
  236. {
  237. const var::identifier name (properties.getName (properties.size() - 1));
  238. properties.remove (name);
  239. sendPropertyChangeMessage (name);
  240. }
  241. }
  242. else
  243. {
  244. for (int i = properties.size(); --i >= 0;)
  245. undoManager->perform (new ValueTreeSetPropertyAction (this, properties.getName(i), var::null, false, true));
  246. }
  247. }
  248. ValueTree ValueTree::SharedObject::getChildWithName (const String& typeToMatch) const
  249. {
  250. for (int i = 0; i < children.size(); ++i)
  251. if (children.getUnchecked(i)->type == typeToMatch)
  252. return ValueTree (static_cast <SharedObject*> (children.getUnchecked(i)));
  253. return ValueTree::invalid;
  254. }
  255. ValueTree ValueTree::SharedObject::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const
  256. {
  257. for (int i = 0; i < children.size(); ++i)
  258. if (children.getUnchecked(i)->getProperty (propertyName) == propertyValue)
  259. return ValueTree (static_cast <SharedObject*> (children.getUnchecked(i)));
  260. return ValueTree::invalid;
  261. }
  262. bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possibleParent) const
  263. {
  264. const SharedObject* p = parent;
  265. while (p != 0)
  266. {
  267. if (p == possibleParent)
  268. return true;
  269. p = p->parent;
  270. }
  271. return false;
  272. }
  273. void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager)
  274. {
  275. if (child != 0 && child->parent != this)
  276. {
  277. if (child != this && ! isAChildOf (child))
  278. {
  279. // You should always make sure that a child is removed from its previous parent before
  280. // adding it somewhere else - otherwise, it's ambiguous as to whether a different
  281. // undomanager should be used when removing it from its current parent..
  282. jassert (child->parent == 0);
  283. if (child->parent != 0)
  284. {
  285. jassert (child->parent->children.indexOf (child) >= 0);
  286. child->parent->removeChild (child->parent->children.indexOf (child), undoManager);
  287. }
  288. if (undoManager == 0)
  289. {
  290. children.insert (index, child);
  291. child->parent = this;
  292. sendChildChangeMessage();
  293. child->sendParentChangeMessage();
  294. }
  295. else
  296. {
  297. undoManager->perform (new ValueTreeChildChangeAction (this, index, child));
  298. }
  299. }
  300. else
  301. {
  302. // You're attempting to create a recursive loop! A node
  303. // can't be a child of one of its own children!
  304. jassertfalse
  305. }
  306. }
  307. }
  308. void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* const undoManager)
  309. {
  310. const SharedObjectPtr child (children [childIndex]);
  311. if (child != 0)
  312. {
  313. if (undoManager == 0)
  314. {
  315. children.remove (childIndex);
  316. child->parent = 0;
  317. sendChildChangeMessage();
  318. child->sendParentChangeMessage();
  319. }
  320. else
  321. {
  322. undoManager->perform (new ValueTreeChildChangeAction (this, childIndex, 0));
  323. }
  324. }
  325. }
  326. void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager)
  327. {
  328. while (children.size() > 0)
  329. removeChild (children.size() - 1, undoManager);
  330. }
  331. //==============================================================================
  332. ValueTree ValueTree::invalid (static_cast <ValueTree::SharedObject*> (0));
  333. ValueTree::ValueTree (const String& type_)
  334. : object (new ValueTree::SharedObject (type_))
  335. {
  336. jassert (type_.isNotEmpty()); // All objects should be given a sensible type name!
  337. }
  338. ValueTree::ValueTree (SharedObject* const object_)
  339. : object (object_)
  340. {
  341. }
  342. ValueTree::ValueTree (const ValueTree& other)
  343. : object (other.object)
  344. {
  345. }
  346. ValueTree& ValueTree::operator= (const ValueTree& other)
  347. {
  348. if (listeners.size() > 0)
  349. {
  350. if (object != 0)
  351. object->valueTreesWithListeners.removeValue (this);
  352. if (other.object != 0)
  353. other.object->valueTreesWithListeners.add (this);
  354. }
  355. object = other.object;
  356. return *this;
  357. }
  358. ValueTree::~ValueTree()
  359. {
  360. if (listeners.size() > 0 && object != 0)
  361. object->valueTreesWithListeners.removeValue (this);
  362. }
  363. bool ValueTree::operator== (const ValueTree& other) const
  364. {
  365. return object == other.object;
  366. }
  367. bool ValueTree::operator!= (const ValueTree& other) const
  368. {
  369. return object != other.object;
  370. }
  371. ValueTree ValueTree::createCopy() const
  372. {
  373. return ValueTree (object != 0 ? new SharedObject (*object) : 0);
  374. }
  375. bool ValueTree::hasType (const String& typeName) const
  376. {
  377. return object != 0 && object->type == typeName;
  378. }
  379. const String ValueTree::getType() const
  380. {
  381. return object != 0 ? object->type : String::empty;
  382. }
  383. ValueTree ValueTree::getParent() const
  384. {
  385. return ValueTree (object != 0 ? object->parent : (SharedObject*) 0);
  386. }
  387. const var& ValueTree::operator[] (const var::identifier& name) const
  388. {
  389. return object == 0 ? var::null : object->getProperty (name);
  390. }
  391. const var& ValueTree::getProperty (const var::identifier& name) const
  392. {
  393. return object == 0 ? var::null : object->getProperty (name);
  394. }
  395. const var ValueTree::getProperty (const var::identifier& name, const var& defaultReturnValue) const
  396. {
  397. return object == 0 ? defaultReturnValue : object->getProperty (name, defaultReturnValue);
  398. }
  399. void ValueTree::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager)
  400. {
  401. jassert (name.name.isNotEmpty());
  402. if (object != 0 && name.name.isNotEmpty())
  403. object->setProperty (name, newValue, undoManager);
  404. }
  405. bool ValueTree::hasProperty (const var::identifier& name) const
  406. {
  407. return object != 0 && object->hasProperty (name);
  408. }
  409. void ValueTree::removeProperty (const var::identifier& name, UndoManager* const undoManager)
  410. {
  411. if (object != 0)
  412. object->removeProperty (name, undoManager);
  413. }
  414. void ValueTree::removeAllProperties (UndoManager* const undoManager)
  415. {
  416. if (object != 0)
  417. object->removeAllProperties (undoManager);
  418. }
  419. int ValueTree::getNumProperties() const
  420. {
  421. return object == 0 ? 0 : object->properties.size();
  422. }
  423. const var::identifier ValueTree::getPropertyName (const int index) const
  424. {
  425. return object == 0 ? var::identifier()
  426. : object->properties.getName (index);
  427. }
  428. //==============================================================================
  429. class ValueTreePropertyValueSource : public Value::ValueSource,
  430. public ValueTree::Listener
  431. {
  432. public:
  433. ValueTreePropertyValueSource (const ValueTree& tree_,
  434. const var::identifier& property_,
  435. UndoManager* const undoManager_)
  436. : tree (tree_),
  437. property (property_),
  438. undoManager (undoManager_)
  439. {
  440. tree.addListener (this);
  441. }
  442. ~ValueTreePropertyValueSource()
  443. {
  444. tree.removeListener (this);
  445. }
  446. const var getValue() const
  447. {
  448. return tree [property];
  449. }
  450. void setValue (const var& newValue)
  451. {
  452. tree.setProperty (property, newValue, undoManager);
  453. }
  454. void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const var::identifier& changedProperty)
  455. {
  456. if (tree == treeWhosePropertyHasChanged && property == changedProperty)
  457. sendChangeMessage (false);
  458. }
  459. void valueTreeChildrenChanged (ValueTree&) {}
  460. void valueTreeParentChanged (ValueTree&) {}
  461. private:
  462. ValueTree tree;
  463. const var::identifier property;
  464. UndoManager* const undoManager;
  465. ValueTreePropertyValueSource& operator= (const ValueTreePropertyValueSource&);
  466. };
  467. Value ValueTree::getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const
  468. {
  469. return Value (new ValueTreePropertyValueSource (*this, name, undoManager));
  470. }
  471. //==============================================================================
  472. int ValueTree::getNumChildren() const
  473. {
  474. return object == 0 ? 0 : object->children.size();
  475. }
  476. ValueTree ValueTree::getChild (int index) const
  477. {
  478. return ValueTree (object != 0 ? (SharedObject*) object->children [index] : (SharedObject*) 0);
  479. }
  480. ValueTree ValueTree::getChildWithName (const String& type) const
  481. {
  482. return object != 0 ? object->getChildWithName (type) : ValueTree::invalid;
  483. }
  484. ValueTree ValueTree::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const
  485. {
  486. return object != 0 ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree::invalid;
  487. }
  488. bool ValueTree::isAChildOf (const ValueTree& possibleParent) const
  489. {
  490. return object != 0 && object->isAChildOf (possibleParent.object);
  491. }
  492. void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager)
  493. {
  494. if (object != 0)
  495. object->addChild (child.object, index, undoManager);
  496. }
  497. void ValueTree::removeChild (const int childIndex, UndoManager* const undoManager)
  498. {
  499. if (object != 0)
  500. object->removeChild (childIndex, undoManager);
  501. }
  502. void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager)
  503. {
  504. if (object != 0)
  505. object->removeChild (object->children.indexOf (child.object), undoManager);
  506. }
  507. void ValueTree::removeAllChildren (UndoManager* const undoManager)
  508. {
  509. if (object != 0)
  510. object->removeAllChildren (undoManager);
  511. }
  512. //==============================================================================
  513. void ValueTree::addListener (Listener* listener)
  514. {
  515. if (listener != 0)
  516. {
  517. if (listeners.size() == 0 && object != 0)
  518. object->valueTreesWithListeners.add (this);
  519. listeners.add (listener);
  520. }
  521. }
  522. void ValueTree::removeListener (Listener* listener)
  523. {
  524. listeners.remove (listener);
  525. if (listeners.size() == 0 && object != 0)
  526. object->valueTreesWithListeners.removeValue (this);
  527. }
  528. //==============================================================================
  529. XmlElement* ValueTree::SharedObject::createXml() const
  530. {
  531. XmlElement* xml = new XmlElement (type);
  532. int i;
  533. for (i = 0; i < properties.size(); ++i)
  534. {
  535. var::identifier name (properties.getName(i));
  536. const var& v = properties [name];
  537. jassert (! v.isObject()); // DynamicObjects can't be stored as XML!
  538. xml->setAttribute (name.name, v.toString());
  539. }
  540. for (i = 0; i < children.size(); ++i)
  541. xml->addChildElement (children.getUnchecked(i)->createXml());
  542. return xml;
  543. }
  544. XmlElement* ValueTree::createXml() const
  545. {
  546. return object != 0 ? object->createXml() : 0;
  547. }
  548. ValueTree ValueTree::fromXml (const XmlElement& xml)
  549. {
  550. ValueTree v (xml.getTagName());
  551. const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
  552. for (int i = 0; i < numAtts; ++i)
  553. v.setProperty (xml.getAttributeName (i), var (xml.getAttributeValue (i)), 0);
  554. forEachXmlChildElement (xml, e)
  555. {
  556. v.addChild (fromXml (*e), -1, 0);
  557. }
  558. return v;
  559. }
  560. //==============================================================================
  561. void ValueTree::writeToStream (OutputStream& output)
  562. {
  563. output.writeString (getType());
  564. const int numProps = getNumProperties();
  565. output.writeCompressedInt (numProps);
  566. int i;
  567. for (i = 0; i < numProps; ++i)
  568. {
  569. const var::identifier name (getPropertyName(i));
  570. output.writeString (name.name);
  571. getProperty(name).writeToStream (output);
  572. }
  573. const int numChildren = getNumChildren();
  574. output.writeCompressedInt (numChildren);
  575. for (i = 0; i < numChildren; ++i)
  576. getChild (i).writeToStream (output);
  577. }
  578. ValueTree ValueTree::readFromStream (InputStream& input)
  579. {
  580. String type (input.readString());
  581. if (type.isEmpty())
  582. return ValueTree::invalid;
  583. ValueTree v (type);
  584. const int numProps = input.readCompressedInt();
  585. if (numProps < 0)
  586. {
  587. jassertfalse // trying to read corrupted data!
  588. return v;
  589. }
  590. int i;
  591. for (i = 0; i < numProps; ++i)
  592. {
  593. const String name (input.readString());
  594. jassert (name.isNotEmpty());
  595. const var value (var::readFromStream (input));
  596. v.setProperty (name, value, 0);
  597. }
  598. const int numChildren = input.readCompressedInt();
  599. for (i = 0; i < numChildren; ++i)
  600. v.addChild (readFromStream (input), -1, 0);
  601. return v;
  602. }
  603. END_JUCE_NAMESPACE