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.

741 lines
30KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "jucer_NewProjectWizard.h"
  18. #include "jucer_ProjectType.h"
  19. #include "jucer_Module.h"
  20. #include "../Project Saving/jucer_ProjectExporter.h"
  21. #include "../Application/jucer_Application.h"
  22. #include "../Application/jucer_MainWindow.h"
  23. struct NewProjectWizardClasses
  24. {
  25. //==============================================================================
  26. static void createFileCreationOptionComboBox (Component& setupComp,
  27. OwnedArray<Component>& itemsCreated,
  28. const StringArray& fileOptions)
  29. {
  30. ComboBox* c = new ComboBox();
  31. itemsCreated.add (c);
  32. setupComp.addChildAndSetID (c, "filesToCreate");
  33. c->addItemList (fileOptions, 1);
  34. c->setSelectedId (1, dontSendNotification);
  35. Label* l = new Label (String::empty, TRANS("Files to Auto-Generate") + ":");
  36. l->attachToComponent (c, true);
  37. itemsCreated.add (l);
  38. c->setBounds ("parent.width / 2 + 160, 10, parent.width - 10, top + 22");
  39. }
  40. static int getFileCreationComboResult (Component& setupComp)
  41. {
  42. if (ComboBox* cb = dynamic_cast<ComboBox*> (setupComp.findChildWithID ("filesToCreate")))
  43. return cb->getSelectedItemIndex();
  44. jassertfalse;
  45. return 0;
  46. }
  47. static void setExecutableNameForAllTargets (Project& project, const String& exeName)
  48. {
  49. for (Project::ExporterIterator exporter (project); exporter.next();)
  50. for (ProjectExporter::ConfigIterator config (*exporter); config.next();)
  51. config->getTargetBinaryName() = exeName;
  52. }
  53. static Project::Item createSourceGroup (Project& project)
  54. {
  55. return project.getMainGroup().addNewSubGroup ("Source", 0);
  56. }
  57. static File& getLastWizardFolder()
  58. {
  59. #if JUCE_WINDOWS
  60. static File lastFolder (File::getSpecialLocation (File::userDocumentsDirectory));
  61. #else
  62. static File lastFolder (File::getSpecialLocation (File::userHomeDirectory));
  63. #endif
  64. return lastFolder;
  65. }
  66. static bool isJuceModulesFolder (const File& f)
  67. {
  68. return f.isDirectory()
  69. && f.getChildFile ("juce_core").isDirectory();
  70. }
  71. static File findDefaultModulesFolder (bool mustContainJuceCoreModule = true)
  72. {
  73. const MainWindowList& windows = IntrojucerApp::getApp().mainWindowList;
  74. for (int i = windows.windows.size(); --i >= 0;)
  75. {
  76. if (Project* p = windows.windows.getUnchecked (i)->getProject())
  77. {
  78. const File f (EnabledModuleList::findDefaultModulesFolder (*p));
  79. if (isJuceModulesFolder (f) || (f.isDirectory() && ! mustContainJuceCoreModule))
  80. return f;
  81. }
  82. }
  83. if (mustContainJuceCoreModule)
  84. return findDefaultModulesFolder (false);
  85. return File::nonexistent;
  86. }
  87. //==============================================================================
  88. struct NewProjectWizard
  89. {
  90. NewProjectWizard() {}
  91. virtual ~NewProjectWizard() {}
  92. //==============================================================================
  93. virtual String getName() = 0;
  94. virtual String getDescription() = 0;
  95. virtual void addSetupItems (Component&, OwnedArray<Component>&) {}
  96. virtual Result processResultsFromSetupItems (Component&) { return Result::ok(); }
  97. virtual bool initialiseProject (Project& project) = 0;
  98. virtual StringArray getDefaultModules()
  99. {
  100. static const char* mods[] =
  101. {
  102. "juce_core",
  103. "juce_events",
  104. "juce_graphics",
  105. "juce_data_structures",
  106. "juce_gui_basics",
  107. "juce_gui_extra",
  108. "juce_cryptography",
  109. "juce_video",
  110. "juce_opengl",
  111. "juce_audio_basics",
  112. "juce_audio_devices",
  113. "juce_audio_formats",
  114. "juce_audio_processors",
  115. nullptr
  116. };
  117. return StringArray (mods);
  118. }
  119. String appTitle;
  120. File targetFolder, projectFile, modulesFolder;
  121. Component* ownerWindow;
  122. StringArray failedFiles;
  123. //==============================================================================
  124. Project* runWizard (Component* window,
  125. const String& projectName,
  126. const File& target)
  127. {
  128. ownerWindow = window;
  129. appTitle = projectName;
  130. targetFolder = target;
  131. if (! targetFolder.exists())
  132. {
  133. if (! targetFolder.createDirectory())
  134. failedFiles.add (targetFolder.getFullPathName());
  135. }
  136. else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder))
  137. {
  138. if (! AlertWindow::showOkCancelBox (AlertWindow::InfoIcon,
  139. TRANS("New Juce Project"),
  140. TRANS("The folder you chose isn't empty - are you sure you want to create the project there?")
  141. + "\n\n"
  142. + TRANS("Any existing files with the same names may be overwritten by the new files.")))
  143. return nullptr;
  144. }
  145. projectFile = targetFolder.getChildFile (File::createLegalFileName (appTitle))
  146. .withFileExtension (Project::projectFileExtension);
  147. ScopedPointer<Project> project (new Project (projectFile));
  148. if (failedFiles.size() == 0)
  149. {
  150. project->setFile (projectFile);
  151. project->setTitle (appTitle);
  152. project->getBundleIdentifier() = project->getDefaultBundleIdentifier();
  153. if (! initialiseProject (*project))
  154. return nullptr;
  155. addDefaultModules (*project);
  156. if (project->save (false, true) != FileBasedDocument::savedOk)
  157. return nullptr;
  158. project->setChangedFlag (false);
  159. }
  160. if (failedFiles.size() > 0)
  161. {
  162. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  163. TRANS("Errors in Creating Project!"),
  164. TRANS("The following files couldn't be written:")
  165. + "\n\n"
  166. + failedFiles.joinIntoString ("\n", 0, 10));
  167. return nullptr;
  168. }
  169. return project.release();
  170. }
  171. bool selectJuceFolder()
  172. {
  173. for (;;)
  174. {
  175. FileChooser fc ("Select your JUCE modules folder...",
  176. findDefaultModulesFolder(),
  177. "*");
  178. if (! fc.browseForDirectory())
  179. return false;
  180. if (isJuceModulesFolder (fc.getResult()))
  181. {
  182. modulesFolder = fc.getResult();
  183. return true;
  184. }
  185. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  186. "Not a valid JUCE modules folder!",
  187. "Please select the folder containing your juce_* modules!\n\n"
  188. "This is required so that the new project can be given some essential core modules.");
  189. }
  190. }
  191. //==============================================================================
  192. File getSourceFilesFolder() const
  193. {
  194. return projectFile.getSiblingFile ("Source");
  195. }
  196. void createSourceFolder()
  197. {
  198. if (! getSourceFilesFolder().createDirectory())
  199. failedFiles.add (getSourceFilesFolder().getFullPathName());
  200. }
  201. void addDefaultModules (Project& project)
  202. {
  203. StringArray mods (getDefaultModules());
  204. ModuleList list;
  205. list.addAllModulesInFolder (modulesFolder);
  206. for (int i = 0; i < mods.size(); ++i)
  207. if (const ModuleDescription* info = list.getModuleWithID (mods[i]))
  208. project.getModules().addModule (info->manifestFile, true);
  209. }
  210. };
  211. //==============================================================================
  212. struct GUIAppWizard : public NewProjectWizard
  213. {
  214. GUIAppWizard() {}
  215. String getName() { return TRANS("GUI Application"); }
  216. String getDescription() { return TRANS("Creates a standard application"); }
  217. void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
  218. {
  219. const String fileOptions[] = { TRANS("Create a Main.cpp file"),
  220. TRANS("Create a Main.cpp file and a basic window"),
  221. TRANS("Don't create any files") };
  222. createFileCreationOptionComboBox (setupComp, itemsCreated,
  223. StringArray (fileOptions, numElementsInArray (fileOptions)));
  224. }
  225. Result processResultsFromSetupItems (Component& setupComp)
  226. {
  227. createMainCpp = createWindow = false;
  228. switch (getFileCreationComboResult (setupComp))
  229. {
  230. case 0: createMainCpp = true; break;
  231. case 1: createMainCpp = createWindow = true; break;
  232. case 2: break;
  233. default: jassertfalse; break;
  234. }
  235. return Result::ok();
  236. }
  237. bool initialiseProject (Project& project)
  238. {
  239. createSourceFolder();
  240. File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");
  241. File contentCompCpp = getSourceFilesFolder().getChildFile ("MainComponent.cpp");
  242. File contentCompH = contentCompCpp.withFileExtension (".h");
  243. String contentCompName = "MainContentComponent";
  244. project.getProjectTypeValue() = ProjectType::getGUIAppTypeName();
  245. Project::Item sourceGroup (createSourceGroup (project));
  246. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  247. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
  248. if (createWindow)
  249. {
  250. appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);
  251. String windowH = project.getFileTemplate ("jucer_ContentCompTemplate_h")
  252. .replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false)
  253. .replace ("CONTENTCOMPCLASS", contentCompName, false)
  254. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (contentCompH), false);
  255. String windowCpp = project.getFileTemplate ("jucer_ContentCompTemplate_cpp")
  256. .replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false)
  257. .replace ("INCLUDE_CORRESPONDING_HEADER", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false)
  258. .replace ("CONTENTCOMPCLASS", contentCompName, false);
  259. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH))
  260. failedFiles.add (contentCompH.getFullPathName());
  261. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompCpp, windowCpp))
  262. failedFiles.add (contentCompCpp.getFullPathName());
  263. sourceGroup.addFile (contentCompCpp, -1, true);
  264. sourceGroup.addFile (contentCompH, -1, false);
  265. }
  266. if (createMainCpp)
  267. {
  268. String mainCpp = project.getFileTemplate (createWindow ? "jucer_MainTemplate_Window_cpp"
  269. : "jucer_MainTemplate_NoWindow_cpp")
  270. .replace ("APPHEADERS", appHeaders, false)
  271. .replace ("APPCLASSNAME", CodeHelpers::makeValidIdentifier (appTitle + "Application", false, true, false), false)
  272. .replace ("APPNAME", CodeHelpers::addEscapeChars (appTitle), false)
  273. .replace ("CONTENTCOMPCLASS", contentCompName, false)
  274. .replace ("ALLOWMORETHANONEINSTANCE", "true", false);
  275. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))
  276. failedFiles.add (mainCppFile.getFullPathName());
  277. sourceGroup.addFile (mainCppFile, -1, true);
  278. }
  279. project.createExporterForCurrentPlatform();
  280. return true;
  281. }
  282. private:
  283. bool createMainCpp, createWindow;
  284. };
  285. //==============================================================================
  286. struct ConsoleAppWizard : public NewProjectWizard
  287. {
  288. ConsoleAppWizard() {}
  289. String getName() { return TRANS("Console Application"); }
  290. String getDescription() { return TRANS("Creates a command-line application with no GUI features"); }
  291. void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
  292. {
  293. const String fileOptions[] = { TRANS("Create a Main.cpp file"),
  294. TRANS("Don't create any files") };
  295. createFileCreationOptionComboBox (setupComp, itemsCreated,
  296. StringArray (fileOptions, numElementsInArray (fileOptions)));
  297. }
  298. Result processResultsFromSetupItems (Component& setupComp)
  299. {
  300. createMainCpp = false;
  301. switch (getFileCreationComboResult (setupComp))
  302. {
  303. case 0: createMainCpp = true; break;
  304. case 1: break;
  305. default: jassertfalse; break;
  306. }
  307. return Result::ok();
  308. }
  309. bool initialiseProject (Project& project)
  310. {
  311. createSourceFolder();
  312. project.getProjectTypeValue() = ProjectType::getConsoleAppTypeName();
  313. Project::Item sourceGroup (createSourceGroup (project));
  314. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  315. if (createMainCpp)
  316. {
  317. File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");
  318. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
  319. String mainCpp = project.getFileTemplate ("jucer_MainConsoleAppTemplate_cpp")
  320. .replace ("APPHEADERS", appHeaders, false);
  321. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))
  322. failedFiles.add (mainCppFile.getFullPathName());
  323. sourceGroup.addFile (mainCppFile, -1, true);
  324. }
  325. project.createExporterForCurrentPlatform();
  326. return true;
  327. }
  328. private:
  329. bool createMainCpp;
  330. };
  331. //==============================================================================
  332. struct AudioPluginAppWizard : public NewProjectWizard
  333. {
  334. AudioPluginAppWizard() {}
  335. String getName() override { return TRANS("Audio Plug-In"); }
  336. String getDescription() override { return TRANS("Creates an audio plugin project"); }
  337. StringArray getDefaultModules() override
  338. {
  339. StringArray s (NewProjectWizard::getDefaultModules());
  340. s.add ("juce_audio_plugin_client");
  341. return s;
  342. }
  343. bool initialiseProject (Project& project) override
  344. {
  345. createSourceFolder();
  346. String filterClassName = CodeHelpers::makeValidIdentifier (appTitle, true, true, false) + "AudioProcessor";
  347. filterClassName = filterClassName.substring (0, 1).toUpperCase() + filterClassName.substring (1);
  348. String editorClassName = filterClassName + "Editor";
  349. File filterCppFile = getSourceFilesFolder().getChildFile ("PluginProcessor.cpp");
  350. File filterHFile = filterCppFile.withFileExtension (".h");
  351. File editorCppFile = getSourceFilesFolder().getChildFile ("PluginEditor.cpp");
  352. File editorHFile = editorCppFile.withFileExtension (".h");
  353. project.getProjectTypeValue() = ProjectType::getAudioPluginTypeName();
  354. Project::Item sourceGroup (createSourceGroup (project));
  355. project.getConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled; // disabled because it interferes with RTAS build on PC
  356. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  357. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), filterCppFile));
  358. String filterCpp = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_cpp")
  359. .replace ("FILTERHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
  360. + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
  361. .replace ("FILTERCLASSNAME", filterClassName, false)
  362. .replace ("EDITORCLASSNAME", editorClassName, false);
  363. String filterH = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_h")
  364. .replace ("APPHEADERS", appHeaders, false)
  365. .replace ("FILTERCLASSNAME", filterClassName, false)
  366. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (filterHFile), false);
  367. String editorCpp = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_cpp")
  368. .replace ("EDITORCPPHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
  369. + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
  370. .replace ("FILTERCLASSNAME", filterClassName, false)
  371. .replace ("EDITORCLASSNAME", editorClassName, false);
  372. String editorH = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_h")
  373. .replace ("EDITORHEADERS", appHeaders + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false)
  374. .replace ("FILTERCLASSNAME", filterClassName, false)
  375. .replace ("EDITORCLASSNAME", editorClassName, false)
  376. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (editorHFile), false);
  377. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterCppFile, filterCpp))
  378. failedFiles.add (filterCppFile.getFullPathName());
  379. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterHFile, filterH))
  380. failedFiles.add (filterHFile.getFullPathName());
  381. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorCppFile, editorCpp))
  382. failedFiles.add (editorCppFile.getFullPathName());
  383. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorHFile, editorH))
  384. failedFiles.add (editorHFile.getFullPathName());
  385. sourceGroup.addFile (filterCppFile, -1, true);
  386. sourceGroup.addFile (filterHFile, -1, false);
  387. sourceGroup.addFile (editorCppFile, -1, true);
  388. sourceGroup.addFile (editorHFile, -1, false);
  389. project.createExporterForCurrentPlatform();
  390. return true;
  391. }
  392. };
  393. //==============================================================================
  394. struct StaticLibraryWizard : public NewProjectWizard
  395. {
  396. StaticLibraryWizard() {}
  397. String getName() override { return TRANS("Static Library"); }
  398. String getDescription() override { return TRANS("Creates a static library"); }
  399. bool initialiseProject (Project& project) override
  400. {
  401. createSourceFolder();
  402. project.getProjectTypeValue() = ProjectType::getStaticLibTypeName();
  403. createSourceGroup (project);
  404. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  405. project.createExporterForCurrentPlatform();
  406. return true;
  407. }
  408. };
  409. //==============================================================================
  410. struct DynamicLibraryWizard : public NewProjectWizard
  411. {
  412. DynamicLibraryWizard() {}
  413. String getName() override { return TRANS("Dynamic Library"); }
  414. String getDescription() override { return TRANS("Creates a dynamic library"); }
  415. bool initialiseProject (Project& project) override
  416. {
  417. createSourceFolder();
  418. project.getProjectTypeValue() = ProjectType::getDynamicLibTypeName();
  419. createSourceGroup (project);
  420. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  421. project.createExporterForCurrentPlatform();
  422. return true;
  423. }
  424. };
  425. //==============================================================================
  426. class WizardComp : public Component,
  427. private ButtonListener,
  428. private ComboBoxListener,
  429. private TextEditorListener
  430. {
  431. public:
  432. WizardComp()
  433. : projectName (TRANS("Project name")),
  434. nameLabel (String::empty, TRANS("Project Name") + ":"),
  435. typeLabel (String::empty, TRANS("Project Type") + ":"),
  436. fileBrowser (FileBrowserComponent::saveMode | FileBrowserComponent::canSelectDirectories,
  437. getLastWizardFolder(), nullptr, nullptr),
  438. fileOutline (String::empty, TRANS("Project Folder") + ":"),
  439. createButton (TRANS("Create") + "..."),
  440. cancelButton (TRANS("Cancel"))
  441. {
  442. setOpaque (true);
  443. setSize (600, 500);
  444. addChildAndSetID (&projectName, "projectName");
  445. projectName.setText ("NewProject");
  446. projectName.setBounds ("100, 14, parent.width / 2 - 10, top + 22");
  447. nameLabel.attachToComponent (&projectName, true);
  448. projectName.addListener (this);
  449. addChildAndSetID (&projectType, "projectType");
  450. projectType.addItemList (getWizardNames(), 1);
  451. projectType.setSelectedId (1, dontSendNotification);
  452. projectType.setBounds ("100, projectName.bottom + 4, projectName.right, top + 22");
  453. typeLabel.attachToComponent (&projectType, true);
  454. projectType.addListener (this);
  455. addChildAndSetID (&fileOutline, "fileOutline");
  456. fileOutline.setColour (GroupComponent::outlineColourId, Colours::black.withAlpha (0.2f));
  457. fileOutline.setTextLabelPosition (Justification::centred);
  458. fileOutline.setBounds ("10, projectType.bottom + 20, projectType.right, parent.height - 10");
  459. addChildAndSetID (&fileBrowser, "fileBrowser");
  460. fileBrowser.setBounds ("fileOutline.left + 10, fileOutline.top + 20, fileOutline.right - 10, fileOutline.bottom - 12");
  461. fileBrowser.setFilenameBoxLabel ("Folder:");
  462. addChildAndSetID (&createButton, "createButton");
  463. createButton.setBounds ("right - 140, bottom - 24, parent.width - 10, parent.height - 10");
  464. createButton.addListener (this);
  465. addChildAndSetID (&cancelButton, "cancelButton");
  466. cancelButton.addShortcut (KeyPress (KeyPress::escapeKey));
  467. cancelButton.setBounds ("right - 140, createButton.top, createButton.left - 10, createButton.bottom");
  468. cancelButton.addListener (this);
  469. updateCustomItems();
  470. updateCreateButton();
  471. }
  472. void paint (Graphics& g) override
  473. {
  474. g.fillAll (Colour::greyLevel (0.93f));
  475. }
  476. void buttonClicked (Button* b) override
  477. {
  478. if (b == &createButton)
  479. {
  480. createProject();
  481. }
  482. else
  483. {
  484. if (MainWindow* mw = dynamic_cast<MainWindow*> (getTopLevelComponent()))
  485. {
  486. #if ! JUCE_MAC
  487. if (IntrojucerApp::getApp().mainWindowList.windows.size() == 1)
  488. mw->setProject (nullptr);
  489. else
  490. #endif
  491. IntrojucerApp::getApp().mainWindowList.closeWindow (mw);
  492. }
  493. }
  494. }
  495. void createProject()
  496. {
  497. MainWindow* mw = Component::findParentComponentOfClass<MainWindow>();
  498. jassert (mw != nullptr);
  499. ScopedPointer<NewProjectWizard> wizard (createWizard());
  500. if (wizard != nullptr)
  501. {
  502. Result result (wizard->processResultsFromSetupItems (*this));
  503. if (result.failed())
  504. {
  505. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  506. TRANS("Create Project"),
  507. result.getErrorMessage());
  508. return;
  509. }
  510. if (! wizard->selectJuceFolder())
  511. return;
  512. ScopedPointer<Project> project (wizard->runWizard (mw, projectName.getText(),
  513. fileBrowser.getSelectedFile (0)));
  514. if (project != nullptr)
  515. mw->setProject (project.release());
  516. }
  517. }
  518. void updateCustomItems()
  519. {
  520. customItems.clear();
  521. ScopedPointer<NewProjectWizard> wizard (createWizard());
  522. if (wizard != nullptr)
  523. wizard->addSetupItems (*this, customItems);
  524. }
  525. void comboBoxChanged (ComboBox*) override
  526. {
  527. updateCustomItems();
  528. }
  529. void textEditorTextChanged (TextEditor&) override
  530. {
  531. updateCreateButton();
  532. fileBrowser.setFileName (File::createLegalFileName (projectName.getText()));
  533. }
  534. private:
  535. ComboBox projectType;
  536. TextEditor projectName;
  537. Label nameLabel, typeLabel;
  538. FileBrowserComponent fileBrowser;
  539. GroupComponent fileOutline;
  540. TextButton createButton, cancelButton;
  541. OwnedArray<Component> customItems;
  542. NewProjectWizard* createWizard()
  543. {
  544. return createWizardType (projectType.getSelectedItemIndex());
  545. }
  546. void updateCreateButton()
  547. {
  548. createButton.setEnabled (projectName.getText().trim().isNotEmpty());
  549. }
  550. };
  551. //==============================================================================
  552. static int getNumWizards()
  553. {
  554. return 5;
  555. }
  556. static NewProjectWizard* createWizardType (int index)
  557. {
  558. switch (index)
  559. {
  560. case 0: return new GUIAppWizard();
  561. case 1: return new ConsoleAppWizard();
  562. case 2: return new AudioPluginAppWizard();
  563. case 3: return new StaticLibraryWizard();
  564. case 4: return new DynamicLibraryWizard();
  565. default: jassertfalse; break;
  566. }
  567. return nullptr;
  568. }
  569. static StringArray getWizardNames()
  570. {
  571. StringArray s;
  572. for (int i = 0; i < getNumWizards(); ++i)
  573. {
  574. ScopedPointer<NewProjectWizard> wiz (createWizardType (i));
  575. s.add (wiz->getName());
  576. }
  577. return s;
  578. }
  579. };
  580. Component* createNewProjectWizardComponent()
  581. {
  582. return new NewProjectWizardClasses::WizardComp();
  583. }