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.

831 lines
28KB

  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 "jucer_ComponentDocument.h"
  19. #include "Component Types/jucer_ComponentTypeManager.h"
  20. #include "../ui/jucer_CoordinatePropertyComponent.h"
  21. //==============================================================================
  22. static const char* const componentDocumentTag = "COMPONENT";
  23. static const char* const componentGroupTag = "COMPONENTS";
  24. static const char* const markersGroupXTag = "MARKERS_X";
  25. static const char* const markersGroupYTag = "MARKERS_Y";
  26. static const char* const markerTag = "MARKER";
  27. static const char* const metadataTagStart = "JUCER_" "COMPONENT_METADATA_START"; // written like this to avoid thinking this file is a component!
  28. static const char* const metadataTagEnd = "JUCER_" "COMPONENT_METADATA_END";
  29. const char* const ComponentDocument::idProperty = "id";
  30. const char* const ComponentDocument::compBoundsProperty = "position";
  31. const char* const ComponentDocument::memberNameProperty = "memberName";
  32. const char* const ComponentDocument::compNameProperty = "name";
  33. const char* const ComponentDocument::markerNameProperty = "name";
  34. const char* const ComponentDocument::markerPosProperty = "position";
  35. //==============================================================================
  36. ComponentDocument::ComponentDocument (Project* project_, const File& cppFile_)
  37. : project (project_),
  38. cppFile (cppFile_),
  39. root (componentDocumentTag),
  40. changedSinceSaved (false)
  41. {
  42. reload();
  43. checkRootObject();
  44. root.addListener (this);
  45. }
  46. ComponentDocument::ComponentDocument (const ComponentDocument& other)
  47. : project (other.project),
  48. cppFile (other.cppFile),
  49. root (other.root.createCopy()),
  50. changedSinceSaved (false)
  51. {
  52. checkRootObject();
  53. root.addListener (this);
  54. }
  55. ComponentDocument::~ComponentDocument()
  56. {
  57. root.removeListener (this);
  58. }
  59. void ComponentDocument::beginNewTransaction()
  60. {
  61. undoManager.beginNewTransaction();
  62. }
  63. void ComponentDocument::changed()
  64. {
  65. changedSinceSaved = true;
  66. }
  67. void ComponentDocument::valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const var::identifier& property)
  68. {
  69. changed();
  70. }
  71. void ComponentDocument::valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged)
  72. {
  73. changed();
  74. }
  75. void ComponentDocument::valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged)
  76. {
  77. changed();
  78. }
  79. bool ComponentDocument::isComponentFile (const File& file)
  80. {
  81. if (! file.hasFileExtension (".cpp"))
  82. return false;
  83. InputStream* in = file.createInputStream();
  84. if (in != 0)
  85. {
  86. BufferedInputStream buf (in, 8192, true);
  87. while (! buf.isExhausted())
  88. if (buf.readNextLine().contains (metadataTagStart))
  89. return true;
  90. }
  91. return false;
  92. }
  93. const String ComponentDocument::getCppTemplate() const { return String (BinaryData::jucer_ComponentTemplate_cpp); }
  94. const String ComponentDocument::getHeaderTemplate() const { return String (BinaryData::jucer_ComponentTemplate_h); }
  95. const String ComponentDocument::getCppContent()
  96. {
  97. MemoryOutputStream cpp, header;
  98. writeCode (cpp, header);
  99. return cpp.toUTF8();
  100. }
  101. const String ComponentDocument::getHeaderContent()
  102. {
  103. MemoryOutputStream cpp, header;
  104. writeCode (cpp, header);
  105. return header.toUTF8();
  106. }
  107. void ComponentDocument::writeCode (OutputStream& cpp, OutputStream& header)
  108. {
  109. CodeGenerator codeGen;
  110. codeGen.className = getClassName().toString();
  111. codeGen.parentClasses = "public Component";
  112. {
  113. MemoryOutputStream metaData;
  114. writeMetadata (metaData);
  115. codeGen.jucerMetadata = metaData.toUTF8();
  116. }
  117. {
  118. String code (getCppTemplate());
  119. String oldContent;
  120. codeGen.applyToCode (code, cppFile, false, project);
  121. customCode.applyTo (code);
  122. cpp << code;
  123. }
  124. {
  125. String code (getHeaderTemplate());
  126. String oldContent;
  127. codeGen.applyToCode (code, cppFile.withFileExtension (".h"), false, project);
  128. customCode.applyTo (code);
  129. header << code;
  130. }
  131. }
  132. void ComponentDocument::writeMetadata (OutputStream& out)
  133. {
  134. out << metadataTagStart << newLine << newLine;
  135. ScopedPointer<XmlElement> xml (root.createXml());
  136. jassert (xml != 0);
  137. if (xml != 0)
  138. xml->writeToStream (out, String::empty, false, false);
  139. out << newLine
  140. << metadataTagEnd << newLine;
  141. }
  142. bool ComponentDocument::save()
  143. {
  144. MemoryOutputStream cpp, header;
  145. writeCode (cpp, header);
  146. bool savedOk = overwriteFileWithNewDataIfDifferent (cppFile, cpp)
  147. && overwriteFileWithNewDataIfDifferent (cppFile.withFileExtension (".h"), header);
  148. if (savedOk)
  149. changedSinceSaved = false;
  150. return savedOk;
  151. }
  152. bool ComponentDocument::reload()
  153. {
  154. String xmlString;
  155. {
  156. InputStream* in = cppFile.createInputStream();
  157. if (in == 0)
  158. return false;
  159. BufferedInputStream buf (in, 8192, true);
  160. String::Concatenator xml (xmlString);
  161. while (! buf.isExhausted())
  162. {
  163. String line (buf.readNextLine());
  164. if (line.contains (metadataTagStart))
  165. {
  166. while (! buf.isExhausted())
  167. {
  168. line = buf.readNextLine();
  169. if (line.contains (metadataTagEnd))
  170. break;
  171. xml.append (line);
  172. xml.append (newLine);
  173. }
  174. break;
  175. }
  176. }
  177. }
  178. XmlDocument doc (xmlString);
  179. ScopedPointer<XmlElement> xml (doc.getDocumentElement());
  180. if (xml != 0 && xml->hasTagName (componentDocumentTag))
  181. {
  182. ValueTree newTree (ValueTree::fromXml (*xml));
  183. if (newTree.isValid())
  184. {
  185. root = newTree;
  186. markersX = 0;
  187. markersY = 0;
  188. checkRootObject();
  189. undoManager.clearUndoHistory();
  190. changedSinceSaved = false;
  191. customCode.reloadFrom (cppFile.loadFileAsString());
  192. return true;
  193. }
  194. }
  195. return false;
  196. }
  197. bool ComponentDocument::hasChangedSinceLastSave()
  198. {
  199. return changedSinceSaved || customCode.needsSaving();
  200. }
  201. void ComponentDocument::createSubTreeIfNotThere (const String& name)
  202. {
  203. if (! root.getChildWithName (name).isValid())
  204. root.addChild (ValueTree (name), -1, 0);
  205. }
  206. void ComponentDocument::checkRootObject()
  207. {
  208. jassert (root.hasType (componentDocumentTag));
  209. createSubTreeIfNotThere (componentGroupTag);
  210. createSubTreeIfNotThere (markersGroupXTag);
  211. createSubTreeIfNotThere (markersGroupYTag);
  212. if (markersX == 0)
  213. markersX = new MarkerList (*this, true);
  214. if (markersY == 0)
  215. markersY = new MarkerList (*this, false);
  216. if (getClassName().toString().isEmpty())
  217. getClassName() = "NewComponent";
  218. if ((int) getCanvasWidth().getValue() <= 0)
  219. getCanvasWidth() = 640;
  220. if ((int) getCanvasHeight().getValue() <= 0)
  221. getCanvasHeight() = 480;
  222. }
  223. //==============================================================================
  224. const int menuItemOffset = 0x63451fa4;
  225. void ComponentDocument::addNewComponentMenuItems (PopupMenu& menu) const
  226. {
  227. const StringArray typeNames (ComponentTypeManager::getInstance()->getTypeNames());
  228. for (int i = 0; i < typeNames.size(); ++i)
  229. menu.addItem (i + menuItemOffset, "New " + typeNames[i]);
  230. }
  231. void ComponentDocument::performNewComponentMenuItem (int menuResultCode)
  232. {
  233. const StringArray typeNames (ComponentTypeManager::getInstance()->getTypeNames());
  234. if (menuResultCode >= menuItemOffset && menuResultCode < menuItemOffset + typeNames.size())
  235. {
  236. ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandler (menuResultCode - menuItemOffset);
  237. jassert (handler != 0);
  238. if (handler != 0)
  239. {
  240. ValueTree state (handler->getXmlTag());
  241. state.setProperty (idProperty, createAlphaNumericUID(), 0);
  242. handler->initialiseNewItem (*this, state);
  243. getComponentGroup().addChild (state, -1, getUndoManager());
  244. }
  245. }
  246. }
  247. //==============================================================================
  248. ValueTree ComponentDocument::getComponentGroup() const
  249. {
  250. return root.getChildWithName (componentGroupTag);
  251. }
  252. int ComponentDocument::getNumComponents() const
  253. {
  254. return getComponentGroup().getNumChildren();
  255. }
  256. const ValueTree ComponentDocument::getComponent (int index) const
  257. {
  258. return getComponentGroup().getChild (index);
  259. }
  260. const ValueTree ComponentDocument::getComponentWithMemberName (const String& name) const
  261. {
  262. return getComponentGroup().getChildWithProperty (memberNameProperty, name);
  263. }
  264. const ValueTree ComponentDocument::getComponentWithID (const String& uid) const
  265. {
  266. return getComponentGroup().getChildWithProperty (idProperty, uid);
  267. }
  268. Component* ComponentDocument::createComponent (int index)
  269. {
  270. const ValueTree v (getComponentGroup().getChild (index));
  271. if (v.isValid())
  272. {
  273. Component* c = ComponentTypeManager::getInstance()->createFromStoredType (*this, v);
  274. c->getProperties().set (jucerIDProperty, v[idProperty]);
  275. jassert (getJucerIDFor (c).isNotEmpty());
  276. return c;
  277. }
  278. return 0;
  279. }
  280. //==============================================================================
  281. const Coordinate ComponentDocument::findMarker (const String& name, bool isHorizontal) const
  282. {
  283. if (name == Coordinate::parentRightMarkerName) return Coordinate ((double) getCanvasWidth().getValue(), isHorizontal);
  284. if (name == Coordinate::parentBottomMarkerName) return Coordinate ((double) getCanvasHeight().getValue(), isHorizontal);
  285. if (name.containsChar ('.'))
  286. {
  287. const String compName (name.upToFirstOccurrenceOf (".", false, false).trim());
  288. const String edge (name.fromFirstOccurrenceOf (".", false, false).trim());
  289. if (compName.isNotEmpty() && edge.isNotEmpty())
  290. {
  291. const ValueTree comp (getComponentWithMemberName (compName));
  292. if (comp.isValid())
  293. {
  294. const RectangleCoordinates coords (getCoordsFor (comp));
  295. if (edge == "left") return coords.left;
  296. if (edge == "right") return coords.right;
  297. if (edge == "top") return coords.top;
  298. if (edge == "bottom") return coords.bottom;
  299. }
  300. }
  301. }
  302. const ValueTree marker (getMarkerList (isHorizontal).getMarkerNamed (name));
  303. if (marker.isValid())
  304. return getMarkerList (isHorizontal).getCoordinate (marker);
  305. return Coordinate (isHorizontal);
  306. }
  307. const RectangleCoordinates ComponentDocument::getCoordsFor (const ValueTree& state) const
  308. {
  309. return RectangleCoordinates (state [compBoundsProperty]);
  310. }
  311. bool ComponentDocument::setCoordsFor (ValueTree& state, const RectangleCoordinates& pr)
  312. {
  313. const String newBoundsString (pr.toString());
  314. if (state[compBoundsProperty] == newBoundsString)
  315. return false;
  316. state.setProperty (compBoundsProperty, newBoundsString, getUndoManager());
  317. return true;
  318. }
  319. void ComponentDocument::addMarkerMenuItem (int i, const Coordinate& coord, const String& name, PopupMenu& menu,
  320. bool isAnchor1, const String& fullCoordName)
  321. {
  322. Coordinate requestedCoord (findMarker (name, coord.isHorizontal()));
  323. menu.addItem (i, name,
  324. ! (name == fullCoordName || requestedCoord.referencesIndirectly (fullCoordName, *this)),
  325. name == (isAnchor1 ? coord.getAnchor1() : coord.getAnchor2()));
  326. }
  327. void ComponentDocument::addComponentMarkerMenuItems (const ValueTree& componentState, const String& coordName,
  328. Coordinate& coord, PopupMenu& menu, bool isAnchor1)
  329. {
  330. const String componentName (componentState [memberNameProperty].toString());
  331. const String fullCoordName (componentName + "." + coordName);
  332. if (coord.isHorizontal())
  333. {
  334. addMarkerMenuItem (1, coord, Coordinate::parentLeftMarkerName, menu, isAnchor1, fullCoordName);
  335. addMarkerMenuItem (2, coord, Coordinate::parentRightMarkerName, menu, isAnchor1, fullCoordName);
  336. menu.addSeparator();
  337. addMarkerMenuItem (3, coord, componentName + ".left", menu, isAnchor1, fullCoordName);
  338. addMarkerMenuItem (4, coord, componentName + ".right", menu, isAnchor1, fullCoordName);
  339. }
  340. else
  341. {
  342. addMarkerMenuItem (1, coord, Coordinate::parentTopMarkerName, menu, isAnchor1, fullCoordName);
  343. addMarkerMenuItem (2, coord, Coordinate::parentBottomMarkerName, menu, isAnchor1, fullCoordName);
  344. menu.addSeparator();
  345. addMarkerMenuItem (3, coord, componentName + ".top", menu, isAnchor1, fullCoordName);
  346. addMarkerMenuItem (4, coord, componentName + ".bottom", menu, isAnchor1, fullCoordName);
  347. }
  348. menu.addSeparator();
  349. const MarkerList& markerList = getMarkerList (coord.isHorizontal());
  350. int i;
  351. for (i = 0; i < markerList.size(); ++i)
  352. addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)), menu, isAnchor1, fullCoordName);
  353. menu.addSeparator();
  354. for (i = 0; i < getNumComponents(); ++i)
  355. {
  356. const String compName (getComponent (i) [memberNameProperty].toString());
  357. if (compName != componentName)
  358. {
  359. if (coord.isHorizontal())
  360. {
  361. addMarkerMenuItem (10000 + i * 4, coord, compName + ".left", menu, isAnchor1, fullCoordName);
  362. addMarkerMenuItem (10001 + i * 4, coord, compName + ".right", menu, isAnchor1, fullCoordName);
  363. }
  364. else
  365. {
  366. addMarkerMenuItem (10002 + i * 4, coord, compName + ".top", menu, isAnchor1, fullCoordName);
  367. addMarkerMenuItem (10003 + i * 4, coord, compName + ".bottom", menu, isAnchor1, fullCoordName);
  368. }
  369. }
  370. }
  371. }
  372. const String ComponentDocument::getChosenMarkerMenuItem (const ValueTree& componentState, Coordinate& coord, int i) const
  373. {
  374. const String componentName (componentState [memberNameProperty].toString());
  375. if (i == 1) return coord.isHorizontal() ? Coordinate::parentLeftMarkerName : Coordinate::parentTopMarkerName;
  376. if (i == 2) return coord.isHorizontal() ? Coordinate::parentRightMarkerName : Coordinate::parentBottomMarkerName;
  377. if (i == 3) return componentName + (coord.isHorizontal() ? ".left" : ".top");
  378. if (i == 4) return componentName + (coord.isHorizontal() ? ".right" : ".bottom");
  379. const MarkerList& markerList = getMarkerList (coord.isHorizontal());
  380. if (i >= 100 && i < 10000)
  381. return markerList.getName (markerList.getMarker (i - 100));
  382. if (i >= 10000)
  383. {
  384. const String compName (getComponent ((i - 10000) / 4) [memberNameProperty].toString());
  385. switch (i & 3)
  386. {
  387. case 0: return compName + ".left";
  388. case 1: return compName + ".right";
  389. case 2: return compName + ".top";
  390. case 3: return compName + ".bottom";
  391. default: break;
  392. }
  393. }
  394. jassertfalse;
  395. return String::empty;
  396. }
  397. void ComponentDocument::updateComponent (Component* comp)
  398. {
  399. const ValueTree v (getComponentState (comp));
  400. if (v.isValid())
  401. {
  402. ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandlerFor (v.getType());
  403. jassert (handler != 0);
  404. if (handler != 0)
  405. handler->updateComponent (*this, comp, v);
  406. }
  407. }
  408. bool ComponentDocument::containsComponent (Component* comp) const
  409. {
  410. const ValueTree comps (getComponentGroup());
  411. for (int i = 0; i < comps.getNumChildren(); ++i)
  412. if (isStateForComponent (comps.getChild(i), comp))
  413. return true;
  414. return false;
  415. }
  416. const ValueTree ComponentDocument::getComponentState (Component* comp) const
  417. {
  418. jassert (comp != 0);
  419. const ValueTree comps (getComponentGroup());
  420. for (int i = 0; i < comps.getNumChildren(); ++i)
  421. if (isStateForComponent (comps.getChild(i), comp))
  422. return comps.getChild(i);
  423. jassertfalse;
  424. return ValueTree::invalid;
  425. }
  426. bool ComponentDocument::isStateForComponent (const ValueTree& storedState, Component* comp) const
  427. {
  428. jassert (comp != 0);
  429. jassert (! storedState [idProperty].isVoid());
  430. return storedState [idProperty] == getJucerIDFor (comp);
  431. }
  432. void ComponentDocument::removeComponent (const ValueTree& state)
  433. {
  434. jassert (state.isAChildOf (getComponentGroup()));
  435. getComponentGroup().removeChild (state, getUndoManager());
  436. }
  437. const String ComponentDocument::getNonExistentMemberName (String suggestedName)
  438. {
  439. suggestedName = makeValidCppIdentifier (suggestedName, false, true, false);
  440. const String original (suggestedName);
  441. int num = 1;
  442. while (getComponentWithMemberName (suggestedName).isValid())
  443. {
  444. suggestedName = original;
  445. while (String ("0123456789").containsChar (suggestedName.getLastCharacter()))
  446. suggestedName = suggestedName.dropLastCharacters (1);
  447. suggestedName << num++;
  448. }
  449. return suggestedName;
  450. }
  451. //==============================================================================
  452. ComponentDocument::MarkerList::MarkerList (ComponentDocument& document_, const bool isX_)
  453. : document (document_),
  454. group (document_.getRoot().getChildWithName (isX_ ? markersGroupXTag : markersGroupYTag)),
  455. isX (isX_)
  456. {
  457. jassert (group.isValid());
  458. jassert (group.isAChildOf (document_.getRoot()));
  459. }
  460. ValueTree& ComponentDocument::MarkerList::getGroup()
  461. {
  462. return group;
  463. }
  464. int ComponentDocument::MarkerList::size() const
  465. {
  466. return group.getNumChildren();
  467. }
  468. ValueTree ComponentDocument::MarkerList::getMarker (int index) const
  469. {
  470. return group.getChild (index);
  471. }
  472. ValueTree ComponentDocument::MarkerList::getMarkerNamed (const String& name) const
  473. {
  474. return group.getChildWithProperty (markerNameProperty, name);
  475. }
  476. bool ComponentDocument::MarkerList::contains (const ValueTree& markerState) const
  477. {
  478. return markerState.isAChildOf (group);
  479. }
  480. const Coordinate ComponentDocument::MarkerList::getCoordinate (const ValueTree& markerState) const
  481. {
  482. return Coordinate (markerState [markerPosProperty].toString(), isX);
  483. }
  484. const String ComponentDocument::MarkerList::getName (const ValueTree& markerState) const
  485. {
  486. return markerState [markerNameProperty].toString();
  487. }
  488. Value ComponentDocument::MarkerList::getNameAsValue (const ValueTree& markerState) const
  489. {
  490. return markerState.getPropertyAsValue (markerNameProperty, document.getUndoManager());
  491. }
  492. void ComponentDocument::MarkerList::setCoordinate (ValueTree& markerState, const Coordinate& newCoord)
  493. {
  494. markerState.setProperty (markerPosProperty, newCoord.toString(), document.getUndoManager());
  495. }
  496. void ComponentDocument::MarkerList::createMarker (const String& name, int position)
  497. {
  498. ValueTree marker (markerTag);
  499. marker.setProperty (markerNameProperty, document.getNonexistentMarkerName (name), 0);
  500. marker.setProperty (markerPosProperty, Coordinate (position, isX).toString(), 0);
  501. marker.setProperty (idProperty, createAlphaNumericUID(), 0);
  502. group.addChild (marker, -1, document.getUndoManager());
  503. }
  504. void ComponentDocument::MarkerList::deleteMarker (ValueTree& markerState)
  505. {
  506. group.removeChild (markerState, document.getUndoManager());
  507. }
  508. const Coordinate ComponentDocument::MarkerList::findMarker (const String& name, bool isHorizontal) const
  509. {
  510. if (isHorizontal == isX)
  511. {
  512. if (name == Coordinate::parentRightMarkerName) return Coordinate ((double) document.getCanvasWidth().getValue(), isHorizontal);
  513. if (name == Coordinate::parentBottomMarkerName) return Coordinate ((double) document.getCanvasHeight().getValue(), isHorizontal);
  514. const ValueTree marker (document.getMarkerList (isHorizontal).getMarkerNamed (name));
  515. if (marker.isValid())
  516. return document.getMarkerList (isHorizontal).getCoordinate (marker);
  517. }
  518. return Coordinate (isX);
  519. }
  520. void ComponentDocument::MarkerList::addMarkerMenuItems (const ValueTree& markerState, const Coordinate& coord, PopupMenu& menu, bool isAnchor1)
  521. {
  522. const String fullCoordName (getName (markerState));
  523. if (coord.isHorizontal())
  524. {
  525. document.addMarkerMenuItem (1, coord, Coordinate::parentLeftMarkerName, menu, isAnchor1, fullCoordName);
  526. document.addMarkerMenuItem (2, coord, Coordinate::parentRightMarkerName, menu, isAnchor1, fullCoordName);
  527. }
  528. else
  529. {
  530. document.addMarkerMenuItem (1, coord, Coordinate::parentTopMarkerName, menu, isAnchor1, fullCoordName);
  531. document.addMarkerMenuItem (2, coord, Coordinate::parentBottomMarkerName, menu, isAnchor1, fullCoordName);
  532. }
  533. menu.addSeparator();
  534. const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
  535. for (int i = 0; i < markerList.size(); ++i)
  536. document.addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)), menu, isAnchor1, fullCoordName);
  537. }
  538. const String ComponentDocument::MarkerList::getChosenMarkerMenuItem (const Coordinate& coord, int i) const
  539. {
  540. if (i == 1) return coord.isHorizontal() ? Coordinate::parentLeftMarkerName : Coordinate::parentTopMarkerName;
  541. if (i == 2) return coord.isHorizontal() ? Coordinate::parentRightMarkerName : Coordinate::parentBottomMarkerName;
  542. const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
  543. if (i >= 100 && i < 10000)
  544. return markerList.getName (markerList.getMarker (i - 100));
  545. jassertfalse;
  546. return String::empty;
  547. }
  548. //==============================================================================
  549. class MarkerPositionComponent : public CoordinatePropertyComponent
  550. {
  551. public:
  552. //==============================================================================
  553. MarkerPositionComponent (ComponentDocument& document_, const String& name, const ValueTree& markerState_,
  554. const Value& coordValue_, bool isHorizontal_)
  555. : CoordinatePropertyComponent (document_, name, coordValue_, isHorizontal_),
  556. markerState (markerState_)
  557. {
  558. }
  559. ~MarkerPositionComponent()
  560. {
  561. }
  562. const String pickMarker (TextButton* button, const String& currentMarker, bool isAnchor1)
  563. {
  564. Coordinate coord (getCoordinate());
  565. PopupMenu m;
  566. document.getMarkerList (coord.isHorizontal())
  567. .addMarkerMenuItems (markerState, coord, m, isAnchor1);
  568. const int r = m.showAt (button);
  569. if (r > 0)
  570. return document.getMarkerList (coord.isHorizontal()).getChosenMarkerMenuItem (coord, r);
  571. return String::empty;
  572. }
  573. private:
  574. ValueTree markerState;
  575. };
  576. void ComponentDocument::MarkerList::createMarkerProperties (Array <PropertyComponent*>& props, ValueTree& marker)
  577. {
  578. props.add (new TextPropertyComponent (getNameAsValue (marker), "Marker Name", 256, false));
  579. props.add (new MarkerPositionComponent (document, "Position", marker,
  580. marker.getPropertyAsValue (markerPosProperty, document.getUndoManager()),
  581. contains (marker)));
  582. }
  583. bool ComponentDocument::MarkerList::createProperties (Array <PropertyComponent*>& props, const String& itemId)
  584. {
  585. ValueTree marker (group.getChildWithProperty (idProperty, itemId));
  586. if (marker.isValid())
  587. {
  588. createMarkerProperties (props, marker);
  589. return true;
  590. }
  591. return false;
  592. }
  593. const String ComponentDocument::getNonexistentMarkerName (const String& name)
  594. {
  595. String n (makeValidCppIdentifier (name, false, true, false));
  596. int suffix = 2;
  597. while (markersX->getMarkerNamed (n).isValid() || markersY->getMarkerNamed (n).isValid())
  598. n = n.trimCharactersAtEnd ("0123456789") + String (suffix++);
  599. return n;
  600. }
  601. //==============================================================================
  602. bool ComponentDocument::createItemProperties (Array <PropertyComponent*>& props, const String& itemId)
  603. {
  604. ValueTree comp (getComponentWithID (itemId));
  605. if (comp.isValid())
  606. {
  607. ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandlerFor (comp.getType());
  608. jassert (handler != 0);
  609. if (handler != 0)
  610. handler->createPropertyEditors (*this, comp, props);
  611. return true;
  612. }
  613. if (markersX->createProperties (props, itemId)
  614. || markersY->createProperties (props, itemId))
  615. return true;
  616. return false;
  617. }
  618. void ComponentDocument::createItemProperties (Array <PropertyComponent*>& props, const StringArray& selectedItemIds)
  619. {
  620. if (selectedItemIds.size() != 1)
  621. return; //xxx
  622. for (int i = 0; i < selectedItemIds.size(); ++i)
  623. createItemProperties (props, selectedItemIds[i]);
  624. }
  625. //==============================================================================
  626. UndoManager* ComponentDocument::getUndoManager() const
  627. {
  628. return &undoManager;
  629. }
  630. //==============================================================================
  631. const char* const ComponentDocument::jucerIDProperty = "jucerID";
  632. const String ComponentDocument::getJucerIDFor (Component* c)
  633. {
  634. if (c == 0)
  635. {
  636. jassertfalse;
  637. return String::empty;
  638. }
  639. jassert (c->getProperties().contains (jucerIDProperty));
  640. return c->getProperties() [jucerIDProperty];
  641. }
  642. //==============================================================================
  643. void ComponentDocument::createClassProperties (Array <PropertyComponent*>& props)
  644. {
  645. props.add (new TextPropertyComponent (getClassName(), "Class Name", 256, false));
  646. props.getLast()->setTooltip ("The C++ class name for the component class.");
  647. props.add (new TextPropertyComponent (getClassDescription(), "Description", 512, false));
  648. props.getLast()->setTooltip ("A freeform description of the component.");
  649. props.add (new SliderPropertyComponent (getCanvasWidth(), "Initial Width", 1.0, 8192.0, 1.0));
  650. props.getLast()->setTooltip ("The initial width of the component when it is created.");
  651. props.add (new SliderPropertyComponent (getCanvasHeight(), "Initial Height", 1.0, 8192.0, 1.0));
  652. props.getLast()->setTooltip ("The initial height of the component when it is created.");
  653. }