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.

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