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.

747 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 "jucer_ComponentDocument.h"
  19. #include "Types/jucer_ComponentTypeManager.h"
  20. #include "../../utility/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 metadataTagStart = "JUCER_" "COMPONENT_METADATA_START"; // written like this to avoid thinking this file is a component!
  27. static const char* const metadataTagEnd = "JUCER_" "COMPONENT_METADATA_END";
  28. const char* const ComponentDocument::idProperty = "id";
  29. const char* const ComponentDocument::compBoundsProperty = "position";
  30. const char* const ComponentDocument::memberNameProperty = "memberName";
  31. const char* const ComponentDocument::compNameProperty = "name";
  32. const char* const ComponentDocument::compTooltipProperty = "tooltip";
  33. const char* const ComponentDocument::compFocusOrderProperty = "focusOrder";
  34. //==============================================================================
  35. ComponentDocument::ComponentDocument (Project* project_, const File& cppFile_)
  36. : project (project_),
  37. cppFile (cppFile_),
  38. root (componentDocumentTag),
  39. changedSinceSaved (false)
  40. {
  41. reload();
  42. checkRootObject();
  43. root.addListener (this);
  44. }
  45. ComponentDocument::ComponentDocument (const ComponentDocument& other)
  46. : project (other.project),
  47. cppFile (other.cppFile),
  48. root (other.root.createCopy()),
  49. changedSinceSaved (false)
  50. {
  51. checkRootObject();
  52. root.addListener (this);
  53. }
  54. ComponentDocument::~ComponentDocument()
  55. {
  56. root.removeListener (this);
  57. }
  58. void ComponentDocument::beginNewTransaction()
  59. {
  60. undoManager.beginNewTransaction();
  61. }
  62. void ComponentDocument::changed()
  63. {
  64. changedSinceSaved = true;
  65. }
  66. void ComponentDocument::valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const var::identifier& property)
  67. {
  68. changed();
  69. }
  70. void ComponentDocument::valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged)
  71. {
  72. changed();
  73. }
  74. void ComponentDocument::valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged)
  75. {
  76. changed();
  77. }
  78. bool ComponentDocument::isComponentFile (const File& file)
  79. {
  80. if (! file.hasFileExtension (".cpp"))
  81. return false;
  82. InputStream* in = file.createInputStream();
  83. if (in != 0)
  84. {
  85. BufferedInputStream buf (in, 8192, true);
  86. while (! buf.isExhausted())
  87. if (buf.readNextLine().contains (metadataTagStart))
  88. return true;
  89. }
  90. return false;
  91. }
  92. const String ComponentDocument::getCppTemplate() const { return String (BinaryData::jucer_ComponentTemplate_cpp); }
  93. const String ComponentDocument::getHeaderTemplate() const { return String (BinaryData::jucer_ComponentTemplate_h); }
  94. const String ComponentDocument::getCppContent()
  95. {
  96. MemoryOutputStream cpp, header;
  97. writeCode (cpp, header);
  98. return cpp.toUTF8();
  99. }
  100. const String ComponentDocument::getHeaderContent()
  101. {
  102. MemoryOutputStream cpp, header;
  103. writeCode (cpp, header);
  104. return header.toUTF8();
  105. }
  106. void ComponentDocument::writeCode (OutputStream& cpp, OutputStream& header)
  107. {
  108. CodeGenerator codeGen;
  109. codeGen.className = getClassName().toString();
  110. codeGen.parentClasses = "public Component";
  111. {
  112. MemoryOutputStream metaData;
  113. writeMetadata (metaData);
  114. codeGen.jucerMetadata = metaData.toUTF8();
  115. }
  116. {
  117. String code (getCppTemplate());
  118. String oldContent;
  119. codeGen.applyToCode (code, cppFile, false, project);
  120. customCode.applyTo (code);
  121. cpp << code;
  122. }
  123. {
  124. String code (getHeaderTemplate());
  125. String oldContent;
  126. codeGen.applyToCode (code, cppFile.withFileExtension (".h"), false, project);
  127. customCode.applyTo (code);
  128. header << code;
  129. }
  130. }
  131. void ComponentDocument::writeMetadata (OutputStream& out)
  132. {
  133. out << metadataTagStart << newLine << newLine;
  134. ScopedPointer<XmlElement> xml (root.createXml());
  135. jassert (xml != 0);
  136. if (xml != 0)
  137. xml->writeToStream (out, String::empty, false, false);
  138. out << newLine << metadataTagEnd;
  139. }
  140. bool ComponentDocument::save()
  141. {
  142. MemoryOutputStream cpp, header;
  143. writeCode (cpp, header);
  144. bool savedOk = overwriteFileWithNewDataIfDifferent (cppFile, cpp)
  145. && overwriteFileWithNewDataIfDifferent (cppFile.withFileExtension (".h"), header);
  146. if (savedOk)
  147. changedSinceSaved = false;
  148. return savedOk;
  149. }
  150. bool ComponentDocument::reload()
  151. {
  152. String xmlString;
  153. {
  154. InputStream* in = cppFile.createInputStream();
  155. if (in == 0)
  156. return false;
  157. BufferedInputStream buf (in, 8192, true);
  158. String::Concatenator xml (xmlString);
  159. while (! buf.isExhausted())
  160. {
  161. String line (buf.readNextLine());
  162. if (line.contains (metadataTagStart))
  163. {
  164. while (! buf.isExhausted())
  165. {
  166. line = buf.readNextLine();
  167. if (line.contains (metadataTagEnd))
  168. break;
  169. xml.append (line);
  170. xml.append (newLine);
  171. }
  172. break;
  173. }
  174. }
  175. }
  176. XmlDocument doc (xmlString);
  177. ScopedPointer<XmlElement> xml (doc.getDocumentElement());
  178. if (xml != 0 && xml->hasTagName (componentDocumentTag))
  179. {
  180. ValueTree newTree (ValueTree::fromXml (*xml));
  181. if (newTree.isValid())
  182. {
  183. root = newTree;
  184. markersX = 0;
  185. markersY = 0;
  186. checkRootObject();
  187. undoManager.clearUndoHistory();
  188. changedSinceSaved = false;
  189. customCode.reloadFrom (cppFile.loadFileAsString());
  190. return true;
  191. }
  192. }
  193. return false;
  194. }
  195. bool ComponentDocument::hasChangedSinceLastSave()
  196. {
  197. return changedSinceSaved || customCode.needsSaving();
  198. }
  199. void ComponentDocument::createSubTreeIfNotThere (const String& name)
  200. {
  201. if (! root.getChildWithName (name).isValid())
  202. root.addChild (ValueTree (name), -1, 0);
  203. }
  204. void ComponentDocument::checkRootObject()
  205. {
  206. jassert (root.hasType (componentDocumentTag));
  207. if (root [idProperty].toString().isEmpty())
  208. root.setProperty (idProperty, createAlphaNumericUID(), 0);
  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. const String ComponentDocument::getNonexistentMemberName (String name)
  320. {
  321. String n (makeValidCppIdentifier (name, false, true, false));
  322. int suffix = 2;
  323. while (markersX->getMarkerNamed (n).isValid() || markersY->getMarkerNamed (n).isValid()
  324. || getComponentWithMemberName (n).isValid())
  325. n = n.trimCharactersAtEnd ("0123456789") + String (suffix++);
  326. return n;
  327. }
  328. void ComponentDocument::renameAnchor (const String& oldName, const String& newName)
  329. {
  330. int i;
  331. for (i = getNumComponents(); --i >= 0;)
  332. {
  333. ValueTree v (getComponent(i));
  334. RectangleCoordinates coords (getCoordsFor (v));
  335. coords.renameAnchorIfUsed (oldName, newName);
  336. setCoordsFor (v, coords);
  337. }
  338. markersX->renameAnchorInMarkers (oldName, newName);
  339. markersY->renameAnchorInMarkers (oldName, newName);
  340. }
  341. void ComponentDocument::addMarkerMenuItem (int i, const Coordinate& coord, const String& name, PopupMenu& menu,
  342. bool isAnchor1, const String& fullCoordName)
  343. {
  344. Coordinate requestedCoord (findMarker (name, coord.isHorizontal()));
  345. menu.addItem (i, name,
  346. ! (name == fullCoordName || requestedCoord.referencesIndirectly (fullCoordName, *this)),
  347. name == (isAnchor1 ? coord.getAnchor1() : coord.getAnchor2()));
  348. }
  349. void ComponentDocument::addComponentMarkerMenuItems (const ValueTree& componentState, const String& coordName,
  350. Coordinate& coord, PopupMenu& menu, bool isAnchor1)
  351. {
  352. const String componentName (componentState [memberNameProperty].toString());
  353. const String fullCoordName (componentName + "." + coordName);
  354. if (coord.isHorizontal())
  355. {
  356. addMarkerMenuItem (1, coord, Coordinate::parentLeftMarkerName, menu, isAnchor1, fullCoordName);
  357. addMarkerMenuItem (2, coord, Coordinate::parentRightMarkerName, menu, isAnchor1, fullCoordName);
  358. menu.addSeparator();
  359. addMarkerMenuItem (3, coord, componentName + ".left", menu, isAnchor1, fullCoordName);
  360. addMarkerMenuItem (4, coord, componentName + ".right", menu, isAnchor1, fullCoordName);
  361. }
  362. else
  363. {
  364. addMarkerMenuItem (1, coord, Coordinate::parentTopMarkerName, menu, isAnchor1, fullCoordName);
  365. addMarkerMenuItem (2, coord, Coordinate::parentBottomMarkerName, menu, isAnchor1, fullCoordName);
  366. menu.addSeparator();
  367. addMarkerMenuItem (3, coord, componentName + ".top", menu, isAnchor1, fullCoordName);
  368. addMarkerMenuItem (4, coord, componentName + ".bottom", menu, isAnchor1, fullCoordName);
  369. }
  370. menu.addSeparator();
  371. const MarkerList& markerList = getMarkerList (coord.isHorizontal());
  372. int i;
  373. for (i = 0; i < markerList.size(); ++i)
  374. addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)), menu, isAnchor1, fullCoordName);
  375. menu.addSeparator();
  376. for (i = 0; i < getNumComponents(); ++i)
  377. {
  378. const String compName (getComponent (i) [memberNameProperty].toString());
  379. if (compName != componentName)
  380. {
  381. if (coord.isHorizontal())
  382. {
  383. addMarkerMenuItem (10000 + i * 4, coord, compName + ".left", menu, isAnchor1, fullCoordName);
  384. addMarkerMenuItem (10001 + i * 4, coord, compName + ".right", menu, isAnchor1, fullCoordName);
  385. }
  386. else
  387. {
  388. addMarkerMenuItem (10002 + i * 4, coord, compName + ".top", menu, isAnchor1, fullCoordName);
  389. addMarkerMenuItem (10003 + i * 4, coord, compName + ".bottom", menu, isAnchor1, fullCoordName);
  390. }
  391. }
  392. }
  393. }
  394. const String ComponentDocument::getChosenMarkerMenuItem (const ValueTree& componentState, Coordinate& coord, int i) const
  395. {
  396. const String componentName (componentState [memberNameProperty].toString());
  397. if (i == 1) return coord.isHorizontal() ? Coordinate::parentLeftMarkerName : Coordinate::parentTopMarkerName;
  398. if (i == 2) return coord.isHorizontal() ? Coordinate::parentRightMarkerName : Coordinate::parentBottomMarkerName;
  399. if (i == 3) return componentName + (coord.isHorizontal() ? ".left" : ".top");
  400. if (i == 4) return componentName + (coord.isHorizontal() ? ".right" : ".bottom");
  401. const MarkerList& markerList = getMarkerList (coord.isHorizontal());
  402. if (i >= 100 && i < 10000)
  403. return markerList.getName (markerList.getMarker (i - 100));
  404. if (i >= 10000)
  405. {
  406. const String compName (getComponent ((i - 10000) / 4) [memberNameProperty].toString());
  407. switch (i & 3)
  408. {
  409. case 0: return compName + ".left";
  410. case 1: return compName + ".right";
  411. case 2: return compName + ".top";
  412. case 3: return compName + ".bottom";
  413. default: break;
  414. }
  415. }
  416. jassertfalse;
  417. return String::empty;
  418. }
  419. void ComponentDocument::updateComponent (Component* comp)
  420. {
  421. const ValueTree v (getComponentState (comp));
  422. if (v.isValid())
  423. {
  424. ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandlerFor (v.getType());
  425. jassert (handler != 0);
  426. if (handler != 0)
  427. handler->updateComponent (*this, comp, v);
  428. }
  429. }
  430. bool ComponentDocument::containsComponent (Component* comp) const
  431. {
  432. const ValueTree comps (getComponentGroup());
  433. for (int i = 0; i < comps.getNumChildren(); ++i)
  434. if (isStateForComponent (comps.getChild(i), comp))
  435. return true;
  436. return false;
  437. }
  438. const ValueTree ComponentDocument::getComponentState (Component* comp) const
  439. {
  440. jassert (comp != 0);
  441. const ValueTree comps (getComponentGroup());
  442. for (int i = 0; i < comps.getNumChildren(); ++i)
  443. if (isStateForComponent (comps.getChild(i), comp))
  444. return comps.getChild(i);
  445. jassertfalse;
  446. return ValueTree::invalid;
  447. }
  448. bool ComponentDocument::isStateForComponent (const ValueTree& storedState, Component* comp) const
  449. {
  450. jassert (comp != 0);
  451. jassert (! storedState [idProperty].isVoid());
  452. return storedState [idProperty] == getJucerIDFor (comp);
  453. }
  454. void ComponentDocument::removeComponent (const ValueTree& state)
  455. {
  456. jassert (state.isAChildOf (getComponentGroup()));
  457. getComponentGroup().removeChild (state, getUndoManager());
  458. }
  459. //==============================================================================
  460. ComponentDocument::MarkerList::MarkerList (ComponentDocument& document_, const bool isX_)
  461. : MarkerListBase (document_.getRoot().getChildWithName (isX_ ? markersGroupXTag : markersGroupYTag), isX_),
  462. document (document_)
  463. {
  464. jassert (group.isValid());
  465. jassert (group.isAChildOf (document_.getRoot()));
  466. }
  467. UndoManager* ComponentDocument::MarkerList::getUndoManager() const
  468. {
  469. return document.getUndoManager();
  470. }
  471. const String ComponentDocument::MarkerList::getNonexistentMarkerName (const String& name)
  472. {
  473. return document.getNonexistentMemberName (name);
  474. }
  475. void ComponentDocument::MarkerList::renameAnchor (const String& oldName, const String& newName)
  476. {
  477. document.renameAnchor (oldName, newName);
  478. }
  479. const Coordinate ComponentDocument::MarkerList::findMarker (const String& name, bool isHorizontal_) const
  480. {
  481. if (isHorizontal_ == isX)
  482. {
  483. if (name == Coordinate::parentRightMarkerName) return Coordinate ((double) document.getCanvasWidth().getValue(), isX);
  484. if (name == Coordinate::parentBottomMarkerName) return Coordinate ((double) document.getCanvasHeight().getValue(), isX);
  485. const ValueTree marker (document.getMarkerList (isX).getMarkerNamed (name));
  486. if (marker.isValid())
  487. return document.getMarkerList (isX).getCoordinate (marker);
  488. }
  489. return Coordinate (isX);
  490. }
  491. void ComponentDocument::MarkerList::addMarkerMenuItems (const ValueTree& markerState, const Coordinate& coord, PopupMenu& menu, bool isAnchor1)
  492. {
  493. const String fullCoordName (getName (markerState));
  494. if (coord.isHorizontal())
  495. {
  496. document.addMarkerMenuItem (1, coord, Coordinate::parentLeftMarkerName, menu, isAnchor1, fullCoordName);
  497. document.addMarkerMenuItem (2, coord, Coordinate::parentRightMarkerName, menu, isAnchor1, fullCoordName);
  498. }
  499. else
  500. {
  501. document.addMarkerMenuItem (1, coord, Coordinate::parentTopMarkerName, menu, isAnchor1, fullCoordName);
  502. document.addMarkerMenuItem (2, coord, Coordinate::parentBottomMarkerName, menu, isAnchor1, fullCoordName);
  503. }
  504. menu.addSeparator();
  505. const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
  506. for (int i = 0; i < markerList.size(); ++i)
  507. document.addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)), menu, isAnchor1, fullCoordName);
  508. }
  509. const String ComponentDocument::MarkerList::getChosenMarkerMenuItem (const Coordinate& coord, int i) const
  510. {
  511. if (i == 1) return coord.isHorizontal() ? Coordinate::parentLeftMarkerName : Coordinate::parentTopMarkerName;
  512. if (i == 2) return coord.isHorizontal() ? Coordinate::parentRightMarkerName : Coordinate::parentBottomMarkerName;
  513. const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
  514. if (i >= 100 && i < 10000)
  515. return markerList.getName (markerList.getMarker (i - 100));
  516. jassertfalse;
  517. return String::empty;
  518. }
  519. //==============================================================================
  520. bool ComponentDocument::MarkerList::createProperties (Array <PropertyComponent*>& props, const String& itemId)
  521. {
  522. ValueTree marker (group.getChildWithProperty (idProperty, itemId));
  523. if (marker.isValid())
  524. {
  525. props.add (new TextPropertyComponent (Value (new MarkerListBase::MarkerNameValueSource (this, getNameAsValue (marker))),
  526. "Marker Name", 256, false));
  527. props.add (new MarkerListBase::PositionPropertyComponent (document, *this, "Position", marker,
  528. marker.getPropertyAsValue (getMarkerPosProperty(), document.getUndoManager())));
  529. return true;
  530. }
  531. return false;
  532. }
  533. //==============================================================================
  534. bool ComponentDocument::createItemProperties (Array <PropertyComponent*>& props, const String& itemId)
  535. {
  536. ValueTree comp (getComponentWithID (itemId));
  537. if (comp.isValid())
  538. {
  539. ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandlerFor (comp.getType());
  540. jassert (handler != 0);
  541. if (handler != 0)
  542. handler->createPropertyEditors (*this, comp, props);
  543. return true;
  544. }
  545. if (markersX->createProperties (props, itemId)
  546. || markersY->createProperties (props, itemId))
  547. return true;
  548. return false;
  549. }
  550. void ComponentDocument::createItemProperties (Array <PropertyComponent*>& props, const StringArray& selectedItemIds)
  551. {
  552. if (selectedItemIds.size() != 1)
  553. return; //xxx
  554. for (int i = 0; i < selectedItemIds.size(); ++i)
  555. createItemProperties (props, selectedItemIds[i]);
  556. }
  557. //==============================================================================
  558. UndoManager* ComponentDocument::getUndoManager() const
  559. {
  560. return &undoManager;
  561. }
  562. //==============================================================================
  563. const char* const ComponentDocument::jucerIDProperty = "jucerID";
  564. const String ComponentDocument::getJucerIDFor (Component* c)
  565. {
  566. if (c == 0)
  567. {
  568. jassertfalse;
  569. return String::empty;
  570. }
  571. jassert (c->getProperties().contains (jucerIDProperty));
  572. return c->getProperties() [jucerIDProperty];
  573. }
  574. //==============================================================================
  575. void ComponentDocument::createClassProperties (Array <PropertyComponent*>& props)
  576. {
  577. props.add (new TextPropertyComponent (getClassName(), "Class Name", 256, false));
  578. props.getLast()->setTooltip ("The C++ class name for the component class.");
  579. props.add (new TextPropertyComponent (getClassDescription(), "Description", 512, false));
  580. props.getLast()->setTooltip ("A freeform description of the component.");
  581. props.add (new SliderPropertyComponent (getCanvasWidth(), "Initial Width", 1.0, 8192.0, 1.0));
  582. props.getLast()->setTooltip ("The initial width of the component when it is created.");
  583. props.add (new SliderPropertyComponent (getCanvasHeight(), "Initial Height", 1.0, 8192.0, 1.0));
  584. props.getLast()->setTooltip ("The initial height of the component when it is created.");
  585. }