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.

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