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.

679 lines
28KB

  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. //==============================================================================
  67. struct NewProjectWizard
  68. {
  69. NewProjectWizard() {}
  70. virtual ~NewProjectWizard() {}
  71. //==============================================================================
  72. virtual String getName() = 0;
  73. virtual String getDescription() = 0;
  74. virtual void addSetupItems (Component&, OwnedArray<Component>&) {}
  75. virtual Result processResultsFromSetupItems (Component&) { return Result::ok(); }
  76. virtual bool initialiseProject (Project& project) = 0;
  77. virtual StringArray getDefaultModules()
  78. {
  79. const char* mods[] =
  80. {
  81. "juce_core",
  82. "juce_events",
  83. "juce_graphics",
  84. "juce_data_structures",
  85. "juce_gui_basics",
  86. "juce_gui_extra",
  87. "juce_cryptography",
  88. "juce_video",
  89. "juce_opengl",
  90. "juce_audio_basics",
  91. "juce_audio_devices",
  92. "juce_audio_formats",
  93. "juce_audio_processors",
  94. nullptr
  95. };
  96. return StringArray (mods);
  97. }
  98. String appTitle;
  99. File targetFolder, projectFile;
  100. Component* ownerWindow;
  101. StringArray failedFiles;
  102. //==============================================================================
  103. Project* runWizard (Component* window,
  104. const String& projectName,
  105. const File& target)
  106. {
  107. ownerWindow = window;
  108. appTitle = projectName;
  109. targetFolder = target;
  110. if (! targetFolder.exists())
  111. {
  112. if (! targetFolder.createDirectory())
  113. failedFiles.add (targetFolder.getFullPathName());
  114. }
  115. else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder))
  116. {
  117. if (! AlertWindow::showOkCancelBox (AlertWindow::InfoIcon,
  118. TRANS("New Juce Project"),
  119. TRANS("The folder you chose isn't empty - are you sure you want to create the project there?")
  120. + "\n\n"
  121. + TRANS("Any existing files with the same names may be overwritten by the new files.")))
  122. return nullptr;
  123. }
  124. projectFile = targetFolder.getChildFile (File::createLegalFileName (appTitle))
  125. .withFileExtension (Project::projectFileExtension);
  126. ScopedPointer<Project> project (new Project (projectFile));
  127. addDefaultModules (*project);
  128. if (failedFiles.size() == 0)
  129. {
  130. project->setFile (projectFile);
  131. project->setTitle (appTitle);
  132. project->getBundleIdentifier() = project->getDefaultBundleIdentifier();
  133. if (! initialiseProject (*project))
  134. return nullptr;
  135. if (project->save (false, true) != FileBasedDocument::savedOk)
  136. return nullptr;
  137. project->setChangedFlag (false);
  138. }
  139. if (failedFiles.size() > 0)
  140. {
  141. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  142. TRANS("Errors in Creating Project!"),
  143. TRANS("The following files couldn't be written:")
  144. + "\n\n"
  145. + failedFiles.joinIntoString ("\n", 0, 10));
  146. return nullptr;
  147. }
  148. return project.release();
  149. }
  150. //==============================================================================
  151. File getSourceFilesFolder() const
  152. {
  153. return projectFile.getSiblingFile ("Source");
  154. }
  155. void createSourceFolder()
  156. {
  157. if (! getSourceFilesFolder().createDirectory())
  158. failedFiles.add (getSourceFilesFolder().getFullPathName());
  159. }
  160. void addDefaultModules (Project& project)
  161. {
  162. StringArray mods (getDefaultModules());
  163. ModuleList list;
  164. list.scanAllKnownFolders (project);
  165. for (int i = 0; i < mods.size(); ++i)
  166. if (const ModuleDescription* info = list.getModuleWithID (mods[i]))
  167. project.getModules().addModule (info->manifestFile, true);
  168. }
  169. };
  170. //==============================================================================
  171. struct GUIAppWizard : public NewProjectWizard
  172. {
  173. GUIAppWizard() {}
  174. String getName() { return TRANS("GUI Application"); }
  175. String getDescription() { return TRANS("Creates a standard application"); }
  176. void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
  177. {
  178. const String fileOptions[] = { TRANS("Create a Main.cpp file"),
  179. TRANS("Create a Main.cpp file and a basic window"),
  180. TRANS("Don't create any files") };
  181. createFileCreationOptionComboBox (setupComp, itemsCreated,
  182. StringArray (fileOptions, numElementsInArray (fileOptions)));
  183. }
  184. Result processResultsFromSetupItems (Component& setupComp)
  185. {
  186. createMainCpp = createWindow = false;
  187. switch (getFileCreationComboResult (setupComp))
  188. {
  189. case 0: createMainCpp = true; break;
  190. case 1: createMainCpp = createWindow = true; break;
  191. case 2: break;
  192. default: jassertfalse; break;
  193. }
  194. return Result::ok();
  195. }
  196. bool initialiseProject (Project& project)
  197. {
  198. createSourceFolder();
  199. File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");
  200. File contentCompCpp = getSourceFilesFolder().getChildFile ("MainComponent.cpp");
  201. File contentCompH = contentCompCpp.withFileExtension (".h");
  202. String contentCompName = "MainContentComponent";
  203. project.getProjectTypeValue() = ProjectType::getGUIAppTypeName();
  204. Project::Item sourceGroup (createSourceGroup (project));
  205. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  206. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
  207. if (createWindow)
  208. {
  209. appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);
  210. String windowH = project.getFileTemplate ("jucer_ContentCompTemplate_h")
  211. .replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false)
  212. .replace ("CONTENTCOMPCLASS", contentCompName, false)
  213. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (contentCompH), false);
  214. String windowCpp = project.getFileTemplate ("jucer_ContentCompTemplate_cpp")
  215. .replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false)
  216. .replace ("INCLUDE_CORRESPONDING_HEADER", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false)
  217. .replace ("CONTENTCOMPCLASS", contentCompName, false);
  218. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH))
  219. failedFiles.add (contentCompH.getFullPathName());
  220. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompCpp, windowCpp))
  221. failedFiles.add (contentCompCpp.getFullPathName());
  222. sourceGroup.addFile (contentCompCpp, -1, true);
  223. sourceGroup.addFile (contentCompH, -1, false);
  224. }
  225. if (createMainCpp)
  226. {
  227. String mainCpp = project.getFileTemplate (createWindow ? "jucer_MainTemplate_Window_cpp"
  228. : "jucer_MainTemplate_NoWindow_cpp")
  229. .replace ("APPHEADERS", appHeaders, false)
  230. .replace ("APPCLASSNAME", CodeHelpers::makeValidIdentifier (appTitle + "Application", false, true, false), false)
  231. .replace ("APPNAME", CodeHelpers::addEscapeChars (appTitle), false)
  232. .replace ("CONTENTCOMPCLASS", contentCompName, false)
  233. .replace ("ALLOWMORETHANONEINSTANCE", "true", false);
  234. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))
  235. failedFiles.add (mainCppFile.getFullPathName());
  236. sourceGroup.addFile (mainCppFile, -1, true);
  237. }
  238. project.createExporterForCurrentPlatform();
  239. return true;
  240. }
  241. private:
  242. bool createMainCpp, createWindow;
  243. };
  244. //==============================================================================
  245. struct ConsoleAppWizard : public NewProjectWizard
  246. {
  247. ConsoleAppWizard() {}
  248. String getName() { return TRANS("Console Application"); }
  249. String getDescription() { return TRANS("Creates a command-line application with no GUI features"); }
  250. void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
  251. {
  252. const String fileOptions[] = { TRANS("Create a Main.cpp file"),
  253. TRANS("Don't create any files") };
  254. createFileCreationOptionComboBox (setupComp, itemsCreated,
  255. StringArray (fileOptions, numElementsInArray (fileOptions)));
  256. }
  257. Result processResultsFromSetupItems (Component& setupComp)
  258. {
  259. createMainCpp = false;
  260. switch (getFileCreationComboResult (setupComp))
  261. {
  262. case 0: createMainCpp = true; break;
  263. case 1: break;
  264. default: jassertfalse; break;
  265. }
  266. return Result::ok();
  267. }
  268. bool initialiseProject (Project& project)
  269. {
  270. createSourceFolder();
  271. project.getProjectTypeValue() = ProjectType::getConsoleAppTypeName();
  272. Project::Item sourceGroup (createSourceGroup (project));
  273. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  274. if (createMainCpp)
  275. {
  276. File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");
  277. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
  278. String mainCpp = project.getFileTemplate ("jucer_MainConsoleAppTemplate_cpp")
  279. .replace ("APPHEADERS", appHeaders, false);
  280. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))
  281. failedFiles.add (mainCppFile.getFullPathName());
  282. sourceGroup.addFile (mainCppFile, -1, true);
  283. }
  284. project.createExporterForCurrentPlatform();
  285. return true;
  286. }
  287. private:
  288. bool createMainCpp;
  289. };
  290. //==============================================================================
  291. struct AudioPluginAppWizard : public NewProjectWizard
  292. {
  293. AudioPluginAppWizard() {}
  294. String getName() override { return TRANS("Audio Plug-In"); }
  295. String getDescription() override { return TRANS("Creates an audio plugin project"); }
  296. StringArray getDefaultModules() override
  297. {
  298. StringArray s (NewProjectWizard::getDefaultModules());
  299. s.add ("juce_audio_plugin_client");
  300. return s;
  301. }
  302. bool initialiseProject (Project& project) override
  303. {
  304. createSourceFolder();
  305. String filterClassName = CodeHelpers::makeValidIdentifier (appTitle, true, true, false) + "AudioProcessor";
  306. filterClassName = filterClassName.substring (0, 1).toUpperCase() + filterClassName.substring (1);
  307. String editorClassName = filterClassName + "Editor";
  308. File filterCppFile = getSourceFilesFolder().getChildFile ("PluginProcessor.cpp");
  309. File filterHFile = filterCppFile.withFileExtension (".h");
  310. File editorCppFile = getSourceFilesFolder().getChildFile ("PluginEditor.cpp");
  311. File editorHFile = editorCppFile.withFileExtension (".h");
  312. project.getProjectTypeValue() = ProjectType::getAudioPluginTypeName();
  313. Project::Item sourceGroup (createSourceGroup (project));
  314. project.getConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled; // disabled because it interferes with RTAS build on PC
  315. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  316. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), filterCppFile));
  317. String filterCpp = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_cpp")
  318. .replace ("FILTERHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
  319. + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
  320. .replace ("FILTERCLASSNAME", filterClassName, false)
  321. .replace ("EDITORCLASSNAME", editorClassName, false);
  322. String filterH = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_h")
  323. .replace ("APPHEADERS", appHeaders, false)
  324. .replace ("FILTERCLASSNAME", filterClassName, false)
  325. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (filterHFile), false);
  326. String editorCpp = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_cpp")
  327. .replace ("EDITORCPPHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
  328. + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
  329. .replace ("FILTERCLASSNAME", filterClassName, false)
  330. .replace ("EDITORCLASSNAME", editorClassName, false);
  331. String editorH = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_h")
  332. .replace ("EDITORHEADERS", appHeaders + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false)
  333. .replace ("FILTERCLASSNAME", filterClassName, false)
  334. .replace ("EDITORCLASSNAME", editorClassName, false)
  335. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (editorHFile), false);
  336. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterCppFile, filterCpp))
  337. failedFiles.add (filterCppFile.getFullPathName());
  338. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterHFile, filterH))
  339. failedFiles.add (filterHFile.getFullPathName());
  340. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorCppFile, editorCpp))
  341. failedFiles.add (editorCppFile.getFullPathName());
  342. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorHFile, editorH))
  343. failedFiles.add (editorHFile.getFullPathName());
  344. sourceGroup.addFile (filterCppFile, -1, true);
  345. sourceGroup.addFile (filterHFile, -1, false);
  346. sourceGroup.addFile (editorCppFile, -1, true);
  347. sourceGroup.addFile (editorHFile, -1, false);
  348. project.createExporterForCurrentPlatform();
  349. return true;
  350. }
  351. };
  352. //==============================================================================
  353. struct StaticLibraryWizard : public NewProjectWizard
  354. {
  355. StaticLibraryWizard() {}
  356. String getName() override { return TRANS("Static Library"); }
  357. String getDescription() override { return TRANS("Creates a static library"); }
  358. bool initialiseProject (Project& project) override
  359. {
  360. createSourceFolder();
  361. project.getProjectTypeValue() = ProjectType::getStaticLibTypeName();
  362. createSourceGroup (project);
  363. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  364. project.createExporterForCurrentPlatform();
  365. return true;
  366. }
  367. };
  368. //==============================================================================
  369. struct DynamicLibraryWizard : public NewProjectWizard
  370. {
  371. DynamicLibraryWizard() {}
  372. String getName() override { return TRANS("Dynamic Library"); }
  373. String getDescription() override { return TRANS("Creates a dynamic library"); }
  374. bool initialiseProject (Project& project) override
  375. {
  376. createSourceFolder();
  377. project.getProjectTypeValue() = ProjectType::getDynamicLibTypeName();
  378. createSourceGroup (project);
  379. setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
  380. project.createExporterForCurrentPlatform();
  381. return true;
  382. }
  383. };
  384. //==============================================================================
  385. class WizardComp : public Component,
  386. private ButtonListener,
  387. private ComboBoxListener,
  388. private TextEditorListener
  389. {
  390. public:
  391. WizardComp()
  392. : projectName (TRANS("Project name")),
  393. nameLabel (String::empty, TRANS("Project Name") + ":"),
  394. typeLabel (String::empty, TRANS("Project Type") + ":"),
  395. fileBrowser (FileBrowserComponent::saveMode | FileBrowserComponent::canSelectDirectories,
  396. getLastWizardFolder(), nullptr, nullptr),
  397. fileOutline (String::empty, TRANS("Project Folder") + ":"),
  398. createButton (TRANS("Create") + "..."),
  399. cancelButton (TRANS("Cancel"))
  400. {
  401. setOpaque (true);
  402. setSize (600, 500);
  403. addChildAndSetID (&projectName, "projectName");
  404. projectName.setText ("NewProject");
  405. projectName.setBounds ("100, 14, parent.width / 2 - 10, top + 22");
  406. nameLabel.attachToComponent (&projectName, true);
  407. projectName.addListener (this);
  408. addChildAndSetID (&projectType, "projectType");
  409. projectType.addItemList (getWizardNames(), 1);
  410. projectType.setSelectedId (1, dontSendNotification);
  411. projectType.setBounds ("100, projectName.bottom + 4, projectName.right, top + 22");
  412. typeLabel.attachToComponent (&projectType, true);
  413. projectType.addListener (this);
  414. addChildAndSetID (&fileOutline, "fileOutline");
  415. fileOutline.setColour (GroupComponent::outlineColourId, Colours::black.withAlpha (0.2f));
  416. fileOutline.setTextLabelPosition (Justification::centred);
  417. fileOutline.setBounds ("10, projectType.bottom + 20, projectType.right, parent.height - 10");
  418. addChildAndSetID (&fileBrowser, "fileBrowser");
  419. fileBrowser.setBounds ("fileOutline.left + 10, fileOutline.top + 20, fileOutline.right - 10, fileOutline.bottom - 12");
  420. fileBrowser.setFilenameBoxLabel ("Folder:");
  421. addChildAndSetID (&createButton, "createButton");
  422. createButton.setBounds ("right - 140, bottom - 24, parent.width - 10, parent.height - 10");
  423. createButton.addListener (this);
  424. addChildAndSetID (&cancelButton, "cancelButton");
  425. cancelButton.addShortcut (KeyPress (KeyPress::escapeKey));
  426. cancelButton.setBounds ("right - 140, createButton.top, createButton.left - 10, createButton.bottom");
  427. cancelButton.addListener (this);
  428. updateCustomItems();
  429. updateCreateButton();
  430. }
  431. void paint (Graphics& g) override
  432. {
  433. g.fillAll (Colour::greyLevel (0.93f));
  434. }
  435. void buttonClicked (Button* b) override
  436. {
  437. if (b == &createButton)
  438. {
  439. createProject();
  440. }
  441. else
  442. {
  443. if (MainWindow* mw = dynamic_cast<MainWindow*> (getTopLevelComponent()))
  444. IntrojucerApp::getApp().mainWindowList.closeWindow (mw);
  445. }
  446. }
  447. void createProject()
  448. {
  449. MainWindow* mw = Component::findParentComponentOfClass<MainWindow>();
  450. jassert (mw != nullptr);
  451. ScopedPointer<NewProjectWizard> wizard (createWizard());
  452. if (wizard != nullptr)
  453. {
  454. Result result (wizard->processResultsFromSetupItems (*this));
  455. if (result.failed())
  456. {
  457. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  458. TRANS("Create Project"),
  459. result.getErrorMessage());
  460. return;
  461. }
  462. ScopedPointer<Project> project (wizard->runWizard (mw, projectName.getText(),
  463. fileBrowser.getSelectedFile (0)));
  464. if (project != nullptr)
  465. mw->setProject (project.release());
  466. }
  467. }
  468. void updateCustomItems()
  469. {
  470. customItems.clear();
  471. ScopedPointer <NewProjectWizard> wizard (createWizard());
  472. if (wizard != nullptr)
  473. wizard->addSetupItems (*this, customItems);
  474. }
  475. void comboBoxChanged (ComboBox*) override
  476. {
  477. updateCustomItems();
  478. }
  479. void textEditorTextChanged (TextEditor&) override
  480. {
  481. updateCreateButton();
  482. fileBrowser.setFileName (File::createLegalFileName (projectName.getText()));
  483. }
  484. private:
  485. ComboBox projectType;
  486. TextEditor projectName;
  487. Label nameLabel, typeLabel;
  488. FileBrowserComponent fileBrowser;
  489. GroupComponent fileOutline;
  490. TextButton createButton, cancelButton;
  491. OwnedArray<Component> customItems;
  492. NewProjectWizard* createWizard()
  493. {
  494. return createWizardType (projectType.getSelectedItemIndex());
  495. }
  496. void updateCreateButton()
  497. {
  498. createButton.setEnabled (projectName.getText().trim().isNotEmpty());
  499. }
  500. };
  501. //==============================================================================
  502. static int getNumWizards()
  503. {
  504. return 5;
  505. }
  506. static NewProjectWizard* createWizardType (int index)
  507. {
  508. switch (index)
  509. {
  510. case 0: return new GUIAppWizard();
  511. case 1: return new ConsoleAppWizard();
  512. case 2: return new AudioPluginAppWizard();
  513. case 3: return new StaticLibraryWizard();
  514. case 4: return new DynamicLibraryWizard();
  515. default: jassertfalse; break;
  516. }
  517. return 0;
  518. }
  519. static StringArray getWizardNames()
  520. {
  521. StringArray s;
  522. for (int i = 0; i < getNumWizards(); ++i)
  523. {
  524. ScopedPointer<NewProjectWizard> wiz (createWizardType (i));
  525. s.add (wiz->getName());
  526. }
  527. return s;
  528. }
  529. };
  530. Component* createNewProjectWizardComponent()
  531. {
  532. return new NewProjectWizardClasses::WizardComp();
  533. }