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.

479 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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 "../Project Saving/jucer_ProjectExporter.h"
  19. #include "../Application/jucer_Application.h"
  20. #include "jucer_ConfigPage.h"
  21. #include "jucer_ModulesPanel.h"
  22. //==============================================================================
  23. void SettingsTreeViewItemBase::showSettingsPage (Component* content)
  24. {
  25. content->setComponentID (getUniqueName());
  26. ScopedPointer<Component> comp (content);
  27. ProjectContentComponent* pcc = getProjectContentComponent();
  28. if (pcc != nullptr)
  29. pcc->setEditorComponent (new PropertyPanelViewport (comp.release()), nullptr);
  30. }
  31. void SettingsTreeViewItemBase::closeSettingsPage()
  32. {
  33. ProjectContentComponent* pcc = getProjectContentComponent();
  34. if (pcc != nullptr)
  35. {
  36. PropertyPanelViewport* ppv = dynamic_cast<PropertyPanelViewport*> (pcc->getEditorComponent());
  37. if (ppv != nullptr && ppv->viewport.getViewedComponent()->getComponentID() == getUniqueName())
  38. pcc->hideEditor();
  39. }
  40. }
  41. //==============================================================================
  42. namespace ProjectSettingsTreeClasses
  43. {
  44. class ConfigItem : public SettingsTreeViewItemBase
  45. {
  46. public:
  47. ConfigItem (const ProjectExporter::BuildConfiguration::Ptr& config_, const String& exporterName_)
  48. : config (config_), exporterName (exporterName_), configTree (config->config)
  49. {
  50. jassert (config != nullptr);
  51. configTree.addListener (this);
  52. }
  53. bool isRoot() const { return false; }
  54. bool isMissing() { return false; }
  55. bool canBeSelected() const { return true; }
  56. bool mightContainSubItems() { return false; }
  57. String getUniqueName() const { return config->project.getProjectUID() + "_config_" + config->getName(); }
  58. String getRenamingName() const { return getDisplayName(); }
  59. String getDisplayName() const { return config->getName(); }
  60. void setName (const String&) {}
  61. const Drawable* getIcon() const { return StoredSettings::getInstance()->getCogIcon(); }
  62. void showDocument() { showSettingsPage (new SettingsComp (config, exporterName)); }
  63. void itemOpennessChanged (bool) {}
  64. void deleteItem()
  65. {
  66. if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Delete Configuration",
  67. "Are you sure you want to delete this configuration?"))
  68. {
  69. closeSettingsPage();
  70. config->removeFromExporter();
  71. }
  72. }
  73. void showPopupMenu()
  74. {
  75. PopupMenu menu;
  76. menu.addItem (1, "Create a copy of this configuration");
  77. menu.addSeparator();
  78. menu.addItem (2, "Delete this configuration");
  79. launchPopupMenu (menu);
  80. }
  81. void handlePopupMenuResult (int resultCode)
  82. {
  83. if (resultCode == 2)
  84. {
  85. deleteAllSelectedItems();
  86. }
  87. else if (resultCode == 1)
  88. {
  89. for (Project::ExporterIterator exporter (config->project); exporter.next();)
  90. {
  91. if (config->config.isAChildOf (exporter.exporter->settings))
  92. {
  93. exporter.exporter->addNewConfiguration (config);
  94. break;
  95. }
  96. }
  97. }
  98. }
  99. var getDragSourceDescription()
  100. {
  101. return getParentItem()->getUniqueName() + "||" + config->getName();
  102. }
  103. void valueTreePropertyChanged (ValueTree&, const Identifier&) { repaintItem(); }
  104. private:
  105. ProjectExporter::BuildConfiguration::Ptr config;
  106. String exporterName;
  107. ValueTree configTree;
  108. //==============================================================================
  109. class SettingsComp : public Component
  110. {
  111. public:
  112. SettingsComp (ProjectExporter::BuildConfiguration* config, const String& exporterName)
  113. {
  114. addAndMakeVisible (&group);
  115. PropertyListBuilder props;
  116. config->createPropertyEditors (props);
  117. group.setProperties (props);
  118. group.setName (exporterName + " / " + config->getName());
  119. parentSizeChanged();
  120. }
  121. void parentSizeChanged() { updateSize (*this, group); }
  122. private:
  123. PropertyGroup group;
  124. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp);
  125. };
  126. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConfigItem);
  127. };
  128. //==============================================================================
  129. class ExporterItem : public SettingsTreeViewItemBase
  130. {
  131. public:
  132. ExporterItem (Project& project_, ProjectExporter* exporter_, int exporterIndex_)
  133. : project (project_), exporter (exporter_), configListTree (exporter->getConfigurations()),
  134. exporterIndex (exporterIndex_)
  135. {
  136. configListTree.addListener (this);
  137. jassert (exporter != nullptr);
  138. }
  139. bool isRoot() const { return false; }
  140. bool canBeSelected() const { return true; }
  141. bool mightContainSubItems() { return exporter->getNumConfigurations() > 0; }
  142. String getUniqueName() const { return project.getProjectUID() + "_exporter_" + String (exporterIndex); }
  143. String getRenamingName() const { return getDisplayName(); }
  144. String getDisplayName() const { return exporter->getName(); }
  145. void setName (const String&) {}
  146. bool isMissing() { return false; }
  147. const Drawable* getIcon() const { return LookAndFeel::getDefaultLookAndFeel().getDefaultDocumentFileImage(); }
  148. void showDocument() { showSettingsPage (new SettingsComp (exporter)); }
  149. void deleteItem()
  150. {
  151. if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Delete Exporter",
  152. "Are you sure you want to delete this export target?"))
  153. {
  154. closeSettingsPage();
  155. ValueTree parent (exporter->settings.getParent());
  156. parent.removeChild (exporter->settings, project.getUndoManagerFor (parent));
  157. }
  158. }
  159. void addSubItems()
  160. {
  161. for (ProjectExporter::ConfigIterator config (*exporter); config.next();)
  162. addSubItem (new ConfigItem (config.config, exporter->getName()));
  163. }
  164. void showPopupMenu()
  165. {
  166. PopupMenu menu;
  167. menu.addItem (1, "Add a new configuration");
  168. menu.addSeparator();
  169. menu.addItem (2, "Delete this exporter");
  170. launchPopupMenu (menu);
  171. }
  172. void handlePopupMenuResult (int resultCode)
  173. {
  174. if (resultCode == 2)
  175. deleteAllSelectedItems();
  176. else if (resultCode == 1)
  177. exporter->addNewConfiguration (nullptr);
  178. }
  179. var getDragSourceDescription()
  180. {
  181. return getParentItem()->getUniqueName() + "/" + String (exporterIndex);
  182. }
  183. bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails)
  184. {
  185. return dragSourceDetails.description.toString().startsWith (getUniqueName());
  186. }
  187. void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex)
  188. {
  189. const int oldIndex = indexOfConfig (dragSourceDetails.description.toString().fromLastOccurrenceOf ("||", false, false));
  190. if (oldIndex >= 0)
  191. configListTree.moveChild (oldIndex, insertIndex, project.getUndoManagerFor (configListTree));
  192. }
  193. int indexOfConfig (const String& configName)
  194. {
  195. int i = 0;
  196. for (ProjectExporter::ConfigIterator config (*exporter); config.next(); ++i)
  197. if (config->getName() == configName)
  198. return i;
  199. return -1;
  200. }
  201. //==============================================================================
  202. void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); }
  203. void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); }
  204. void valueTreeChildOrderChanged (ValueTree& parentTree) { refreshIfNeeded (parentTree); }
  205. void refreshIfNeeded (ValueTree& changedTree)
  206. {
  207. if (changedTree == configListTree)
  208. refreshSubItems();
  209. }
  210. private:
  211. Project& project;
  212. ScopedPointer<ProjectExporter> exporter;
  213. ValueTree configListTree;
  214. int exporterIndex;
  215. //==============================================================================
  216. class SettingsComp : public Component
  217. {
  218. public:
  219. SettingsComp (ProjectExporter* exporter)
  220. {
  221. addAndMakeVisible (&group);
  222. PropertyListBuilder props;
  223. exporter->createPropertyEditors (props);
  224. group.setProperties (props);
  225. group.setName ("Export target: " + exporter->getName());
  226. parentSizeChanged();
  227. }
  228. void parentSizeChanged() { updateSize (*this, group); }
  229. private:
  230. PropertyGroup group;
  231. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp);
  232. };
  233. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExporterItem);
  234. };
  235. //==============================================================================
  236. class ModulesItem : public SettingsTreeViewItemBase
  237. {
  238. public:
  239. ModulesItem (Project& project_) : project (project_) {}
  240. bool isRoot() const { return false; }
  241. bool canBeSelected() const { return true; }
  242. bool mightContainSubItems() { return false; }
  243. String getUniqueName() const { return project.getProjectUID() + "_modules"; }
  244. String getRenamingName() const { return getDisplayName(); }
  245. String getDisplayName() const { return "Modules"; }
  246. void setName (const String&) {}
  247. bool isMissing() { return false; }
  248. const Drawable* getIcon() const { return project.getMainGroup().getIcon(); }
  249. void showDocument() { showSettingsPage (new SettingsComp (project)); }
  250. private:
  251. Project& project;
  252. //==============================================================================
  253. class SettingsComp : public Component
  254. {
  255. public:
  256. SettingsComp (Project& project_) : project (project_)
  257. {
  258. addAndMakeVisible (&group);
  259. PropertyListBuilder props;
  260. props.add (new ModulesPanel (project));
  261. group.setProperties (props);
  262. group.setName ("Modules");
  263. parentSizeChanged();
  264. }
  265. void parentSizeChanged()
  266. {
  267. updateSize (*this, group);
  268. }
  269. private:
  270. Project& project;
  271. var lastProjectType;
  272. PropertyGroup group;
  273. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp);
  274. };
  275. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesItem);
  276. };
  277. //==============================================================================
  278. class RootItem : public SettingsTreeViewItemBase
  279. {
  280. public:
  281. RootItem (Project& project_)
  282. : project (project_), exportersTree (project_.getExporters())
  283. {
  284. exportersTree.addListener (this);
  285. }
  286. bool isRoot() const { return true; }
  287. String getRenamingName() const { return getDisplayName(); }
  288. String getDisplayName() const { return project.getTitle(); }
  289. void setName (const String&) {}
  290. bool isMissing() { return false; }
  291. const Drawable* getIcon() const { return project.getMainGroup().getIcon(); }
  292. void showDocument() { showSettingsPage (new SettingsComp (project)); }
  293. bool canBeSelected() const { return true; }
  294. bool mightContainSubItems() { return project.getNumExporters() > 0; }
  295. String getUniqueName() const { return project.getProjectUID() + "_config_root"; }
  296. void addSubItems()
  297. {
  298. addSubItem (new ModulesItem (project));
  299. int i = 0;
  300. for (Project::ExporterIterator exporter (project); exporter.next(); ++i)
  301. addSubItem (new ExporterItem (project, exporter.exporter.release(), i));
  302. JucerApplication::getApp()->addExtraConfigItems (project, *this);
  303. }
  304. void showPopupMenu()
  305. {
  306. PopupMenu menu;
  307. const StringArray exporters (ProjectExporter::getExporterNames());
  308. for (int i = 0; i < exporters.size(); ++i)
  309. menu.addItem (i + 1, "Create a new " + exporters[i] + " target");
  310. launchPopupMenu (menu);
  311. }
  312. void handlePopupMenuResult (int resultCode)
  313. {
  314. if (resultCode > 0)
  315. {
  316. String exporterName (ProjectExporter::getExporterNames() [resultCode - 1]);
  317. if (exporterName.isNotEmpty())
  318. project.addNewExporter (exporterName);
  319. }
  320. }
  321. bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails)
  322. {
  323. return dragSourceDetails.description.toString().startsWith (getUniqueName());
  324. }
  325. void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex)
  326. {
  327. int oldIndex = dragSourceDetails.description.toString().getTrailingIntValue();
  328. exportersTree.moveChild (oldIndex, insertIndex, project.getUndoManagerFor (exportersTree));
  329. }
  330. //==============================================================================
  331. void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); }
  332. void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); }
  333. void valueTreeChildOrderChanged (ValueTree& parentTree) { refreshIfNeeded (parentTree); }
  334. void refreshIfNeeded (ValueTree& changedTree)
  335. {
  336. if (changedTree == exportersTree)
  337. refreshSubItems();
  338. }
  339. private:
  340. Project& project;
  341. ValueTree exportersTree;
  342. //==============================================================================
  343. class SettingsComp : public Component,
  344. private ChangeListener
  345. {
  346. public:
  347. SettingsComp (Project& project_)
  348. : project (project_)
  349. {
  350. addAndMakeVisible (&group);
  351. updatePropertyList();
  352. project.addChangeListener (this);
  353. }
  354. ~SettingsComp()
  355. {
  356. project.removeChangeListener (this);
  357. }
  358. void parentSizeChanged()
  359. {
  360. updateSize (*this, group);
  361. }
  362. void updatePropertyList()
  363. {
  364. PropertyListBuilder props;
  365. project.createPropertyEditors (props);
  366. group.setProperties (props);
  367. group.setName ("Project Settings");
  368. lastProjectType = project.getProjectTypeValue().getValue();
  369. parentSizeChanged();
  370. }
  371. void changeListenerCallback (ChangeBroadcaster*)
  372. {
  373. if (lastProjectType != project.getProjectTypeValue().getValue())
  374. updatePropertyList();
  375. }
  376. private:
  377. Project& project;
  378. var lastProjectType;
  379. PropertyGroup group;
  380. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp);
  381. };
  382. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RootItem);
  383. };
  384. }
  385. JucerTreeViewBase* createProjectConfigTreeViewRoot (Project& project)
  386. {
  387. return new ProjectSettingsTreeClasses::RootItem (project);
  388. }