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.

482 lines
19KB

  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 "jucer_NewProjectWizard.h"
  19. #include "jucer_ProjectType.h"
  20. #include "jucer_Module.h"
  21. //==============================================================================
  22. class GUIAppWizard : public NewProjectWizard
  23. {
  24. public:
  25. GUIAppWizard() {}
  26. String getName() { return "GUI Application"; }
  27. String getDescription() { return "Creates a standard application"; }
  28. void addItemsToAlertWindow (AlertWindow& aw)
  29. {
  30. const char* fileOptions[] = { "Create a Main.cpp file",
  31. "Create a Main.cpp file and a basic window",
  32. "Don't create any files", 0 };
  33. aw.addComboBox ("files", StringArray (fileOptions), "Files to Auto-Generate");
  34. }
  35. String processResultsFromAlertWindow (AlertWindow& aw)
  36. {
  37. createMainCpp = createWindow = false;
  38. switch (aw.getComboBoxComponent ("files")->getSelectedItemIndex())
  39. {
  40. case 0: createMainCpp = true; break;
  41. case 1: createMainCpp = createWindow = true; break;
  42. case 2: break;
  43. default: jassertfalse; break;
  44. }
  45. return String::empty;
  46. }
  47. bool initialiseProject (Project& project)
  48. {
  49. if (! getSourceFilesFolder().createDirectory())
  50. failedFiles.add (getSourceFilesFolder().getFullPathName());
  51. File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");
  52. File mainWindowCpp = getSourceFilesFolder().getChildFile ("MainWindow.cpp");
  53. File mainWindowH = mainWindowCpp.withFileExtension (".h");
  54. String windowClassName = "MainAppWindow";
  55. project.getProjectTypeValue() = ProjectType::getGUIAppTypeName();
  56. Project::Item sourceGroup (project.getMainGroup().addNewSubGroup ("Source", 0));
  57. for (int i = project.getNumConfigurations(); --i >= 0;)
  58. project.getConfiguration(i).getTargetBinaryName() = File::createLegalFileName (appTitle);
  59. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
  60. String initCode, shutdownCode, anotherInstanceStartedCode, privateMembers, memberInitialisers;
  61. if (createWindow)
  62. {
  63. appHeaders << newLine << CodeHelpers::createIncludeStatement (mainWindowH, mainCppFile);
  64. initCode = "mainWindow = new " + windowClassName + "();";
  65. shutdownCode = "mainWindow = 0;";
  66. privateMembers = "ScopedPointer <" + windowClassName + "> mainWindow;";
  67. String windowH = project.getFileTemplate ("jucer_WindowTemplate_h")
  68. .replace ("INCLUDES", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainWindowH), false)
  69. .replace ("WINDOWCLASS", windowClassName, false)
  70. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (mainWindowH), false);
  71. String windowCpp = project.getFileTemplate ("jucer_WindowTemplate_cpp")
  72. .replace ("INCLUDES", CodeHelpers::createIncludeStatement (mainWindowH, mainWindowCpp), false)
  73. .replace ("WINDOWCLASS", windowClassName, false);
  74. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainWindowH, windowH))
  75. failedFiles.add (mainWindowH.getFullPathName());
  76. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainWindowCpp, windowCpp))
  77. failedFiles.add (mainWindowCpp.getFullPathName());
  78. sourceGroup.addFile (mainWindowCpp, -1, true);
  79. sourceGroup.addFile (mainWindowH, -1, false);
  80. }
  81. if (createMainCpp)
  82. {
  83. String mainCpp = project.getFileTemplate ("jucer_MainTemplate_cpp")
  84. .replace ("APPHEADERS", appHeaders, false)
  85. .replace ("APPCLASSNAME", CodeHelpers::makeValidIdentifier (appTitle + "Application", false, true, false), false)
  86. .replace ("MEMBERINITIALISERS", memberInitialisers, false)
  87. .replace ("APPINITCODE", initCode, false)
  88. .replace ("APPSHUTDOWNCODE", shutdownCode, false)
  89. .replace ("APPNAME", CodeHelpers::addEscapeChars (appTitle), false)
  90. .replace ("APPVERSION", "1.0", false)
  91. .replace ("ALLOWMORETHANONEINSTANCE", "true", false)
  92. .replace ("ANOTHERINSTANCECODE", anotherInstanceStartedCode, false)
  93. .replace ("PRIVATEMEMBERS", privateMembers, false);
  94. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))
  95. failedFiles.add (mainCppFile.getFullPathName());
  96. sourceGroup.addFile (mainCppFile, -1, true);
  97. }
  98. return true;
  99. }
  100. private:
  101. bool createMainCpp, createWindow;
  102. };
  103. //==============================================================================
  104. class ConsoleAppWizard : public NewProjectWizard
  105. {
  106. public:
  107. ConsoleAppWizard() {}
  108. String getName() { return "Console Application"; }
  109. String getDescription() { return "Creates a command-line application with no GUI features"; }
  110. void addItemsToAlertWindow (AlertWindow& aw)
  111. {
  112. const char* fileOptions[] = { "Create a Main.cpp file",
  113. "Don't create any files", 0 };
  114. aw.addComboBox ("files", StringArray (fileOptions), "Files to Auto-Generate");
  115. }
  116. String processResultsFromAlertWindow (AlertWindow& aw)
  117. {
  118. createMainCpp = false;
  119. switch (aw.getComboBoxComponent ("files")->getSelectedItemIndex())
  120. {
  121. case 0: createMainCpp = true; break;
  122. case 1: break;
  123. default: jassertfalse; break;
  124. }
  125. return String::empty;
  126. }
  127. bool initialiseProject (Project& project)
  128. {
  129. if (! getSourceFilesFolder().createDirectory())
  130. failedFiles.add (getSourceFilesFolder().getFullPathName());
  131. File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");
  132. project.getProjectTypeValue() = ProjectType::getConsoleAppTypeName();
  133. Project::Item sourceGroup (project.getMainGroup().addNewSubGroup ("Source", 0));
  134. for (int i = project.getNumConfigurations(); --i >= 0;)
  135. project.getConfiguration(i).getTargetBinaryName() = File::createLegalFileName (appTitle);
  136. if (createMainCpp)
  137. {
  138. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
  139. String mainCpp = project.getFileTemplate ("jucer_MainConsoleAppTemplate_cpp")
  140. .replace ("APPHEADERS", appHeaders, false);
  141. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))
  142. failedFiles.add (mainCppFile.getFullPathName());
  143. sourceGroup.addFile (mainCppFile, -1, true);
  144. }
  145. return true;
  146. }
  147. private:
  148. bool createMainCpp;
  149. };
  150. //==============================================================================
  151. class AudioPluginAppWizard : public NewProjectWizard
  152. {
  153. public:
  154. AudioPluginAppWizard() {}
  155. String getName() { return "Audio Plug-In"; }
  156. String getDescription() { return "Creates an audio plugin project"; }
  157. void addItemsToAlertWindow (AlertWindow& aw)
  158. {
  159. }
  160. String processResultsFromAlertWindow (AlertWindow& aw)
  161. {
  162. return String::empty;
  163. }
  164. bool initialiseProject (Project& project)
  165. {
  166. if (! getSourceFilesFolder().createDirectory())
  167. failedFiles.add (getSourceFilesFolder().getFullPathName());
  168. String filterClassName = CodeHelpers::makeValidIdentifier (appTitle, true, true, false) + "AudioProcessor";
  169. filterClassName = filterClassName.substring (0, 1).toUpperCase() + filterClassName.substring (1);
  170. String editorClassName = filterClassName + "Editor";
  171. File filterCppFile = getSourceFilesFolder().getChildFile ("PluginProcessor.cpp");
  172. File filterHFile = filterCppFile.withFileExtension (".h");
  173. File editorCppFile = getSourceFilesFolder().getChildFile ("PluginEditor.cpp");
  174. File editorHFile = editorCppFile.withFileExtension (".h");
  175. project.getProjectTypeValue() = ProjectType::getAudioPluginTypeName();
  176. project.addModule ("juce_audio_plugin_client");
  177. Project::Item sourceGroup (project.getMainGroup().addNewSubGroup ("Source", 0));
  178. project.getConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled; // disabled because it interferes with RTAS build on PC
  179. for (int i = project.getNumConfigurations(); --i >= 0;)
  180. project.getConfiguration(i).getTargetBinaryName() = File::createLegalFileName (appTitle);
  181. String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), filterCppFile));
  182. String filterCpp = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_cpp")
  183. .replace ("FILTERHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
  184. + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
  185. .replace ("FILTERCLASSNAME", filterClassName, false)
  186. .replace ("EDITORCLASSNAME", editorClassName, false);
  187. String filterH = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_h")
  188. .replace ("APPHEADERS", appHeaders, false)
  189. .replace ("FILTERCLASSNAME", filterClassName, false)
  190. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (filterHFile), false);
  191. String editorCpp = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_cpp")
  192. .replace ("EDITORCPPHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
  193. + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
  194. .replace ("FILTERCLASSNAME", filterClassName, false)
  195. .replace ("EDITORCLASSNAME", editorClassName, false);
  196. String editorH = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_h")
  197. .replace ("EDITORHEADERS", appHeaders + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false)
  198. .replace ("FILTERCLASSNAME", filterClassName, false)
  199. .replace ("EDITORCLASSNAME", editorClassName, false)
  200. .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (editorHFile), false);
  201. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterCppFile, filterCpp))
  202. failedFiles.add (filterCppFile.getFullPathName());
  203. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterHFile, filterH))
  204. failedFiles.add (filterHFile.getFullPathName());
  205. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorCppFile, editorCpp))
  206. failedFiles.add (editorCppFile.getFullPathName());
  207. if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorHFile, editorH))
  208. failedFiles.add (editorHFile.getFullPathName());
  209. sourceGroup.addFile (filterCppFile, -1, true);
  210. sourceGroup.addFile (filterHFile, -1, false);
  211. sourceGroup.addFile (editorCppFile, -1, true);
  212. sourceGroup.addFile (editorHFile, -1, false);
  213. return true;
  214. }
  215. };
  216. //==============================================================================
  217. /*class BrowserPluginAppWizard : public NewProjectWizard
  218. {
  219. public:
  220. BrowserPluginAppWizard() {}
  221. ~BrowserPluginAppWizard() {}
  222. String getName() { return "Browser Plug-In"; }
  223. String getDescription() { return "Creates an audio plugin project"; }
  224. void addItemsToAlertWindow (AlertWindow& aw)
  225. {
  226. }
  227. String processResultsFromAlertWindow (AlertWindow& aw)
  228. {
  229. return String::empty;
  230. }
  231. bool initialiseProject (Project& project)
  232. {
  233. return true;
  234. }
  235. };*/
  236. //==============================================================================
  237. //==============================================================================
  238. NewProjectWizard::NewProjectWizard() {}
  239. NewProjectWizard::~NewProjectWizard() {}
  240. StringArray NewProjectWizard::getWizards()
  241. {
  242. StringArray s;
  243. for (int i = 0; i < getNumWizards(); ++i)
  244. {
  245. ScopedPointer <NewProjectWizard> wiz (createWizard (i));
  246. s.add (wiz->getName());
  247. }
  248. return s;
  249. }
  250. int NewProjectWizard::getNumWizards()
  251. {
  252. return 3;
  253. }
  254. NewProjectWizard* NewProjectWizard::createWizard (int index)
  255. {
  256. switch (index)
  257. {
  258. case 0: return new GUIAppWizard();
  259. case 1: return new ConsoleAppWizard();
  260. case 2: return new AudioPluginAppWizard();
  261. //case 3: return new BrowserPluginAppWizard();
  262. default: jassertfalse; break;
  263. }
  264. return 0;
  265. }
  266. //==============================================================================
  267. Project* NewProjectWizard::runWizard (Component* ownerWindow_)
  268. {
  269. ownerWindow = ownerWindow_;
  270. {
  271. static File newProjectFolder;
  272. FileChooser fc ("New Juce Project", newProjectFolder, "*");
  273. if (! fc.browseForDirectory())
  274. return 0;
  275. targetFolder = newProjectFolder = fc.getResult();
  276. if (! newProjectFolder.exists())
  277. {
  278. if (! newProjectFolder.createDirectory())
  279. failedFiles.add (newProjectFolder.getFullPathName());
  280. }
  281. if (FileHelpers::containsAnyNonHiddenFiles (newProjectFolder))
  282. {
  283. if (! AlertWindow::showOkCancelBox (AlertWindow::InfoIcon, "New Juce Project",
  284. "The folder you chose isn't empty - are you sure you want to create the project there?\n\nAny existing files with the same names may be overwritten by the new files."))
  285. return 0;
  286. }
  287. }
  288. if (failedFiles.size() == 0)
  289. {
  290. AlertWindow aw ("New " + getName(),
  291. "Please choose some basic project options...",
  292. AlertWindow::NoIcon, ownerWindow);
  293. aw.addTextEditor ("name", "", "Project Name", false);
  294. addItemsToAlertWindow (aw);
  295. aw.addButton ("Create Project", 1, KeyPress (KeyPress::returnKey));
  296. aw.addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey));
  297. for (;;)
  298. {
  299. if (aw.runModalLoop() == 0)
  300. return 0;
  301. appTitle = aw.getTextEditorContents ("name").trim();
  302. String error (processResultsFromAlertWindow (aw));
  303. if (error.isEmpty() && appTitle.isEmpty())
  304. error = "Please enter a sensible project title!";
  305. if (error.isEmpty())
  306. break;
  307. aw.setColour (AlertWindow::textColourId, Colours::red);
  308. aw.setMessage (error);
  309. }
  310. }
  311. projectFile = targetFolder.getChildFile (File::createLegalFileName (appTitle))
  312. .withFileExtension (Project::projectFileExtension);
  313. ScopedPointer<Project> project (new Project (projectFile));
  314. if (failedFiles.size() == 0)
  315. {
  316. project->setFile (projectFile);
  317. project->setTitle (appTitle);
  318. project->setBundleIdentifierToDefault();
  319. if (! initialiseProject (*project))
  320. return 0;
  321. if (project->save (false, true) != FileBasedDocument::savedOk)
  322. return 0;
  323. project->setChangedFlag (false);
  324. }
  325. if (failedFiles.size() > 0)
  326. {
  327. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  328. "Errors in Creating Project!",
  329. "The following files couldn't be written:\n\n"
  330. + failedFiles.joinIntoString ("\n", 0, 10));
  331. return 0;
  332. }
  333. return project.release();
  334. }
  335. Project* NewProjectWizard::runNewProjectWizard (Component* ownerWindow)
  336. {
  337. ScopedPointer <NewProjectWizard> wizard;
  338. {
  339. AlertWindow aw ("New Juce Project",
  340. "Select the type of project to create, and the location of your Juce folder",
  341. AlertWindow::NoIcon,
  342. ownerWindow);
  343. aw.addComboBox ("type", getWizards(), "Project Type");
  344. FilenameComponent juceFolderSelector ("Juce Library Location", ModuleList::getLocalModulesFolder (nullptr),
  345. true, true, false, "*", String::empty, "(Please select the folder containing Juce!)");
  346. juceFolderSelector.setSize (350, 22);
  347. aw.addCustomComponent (&juceFolderSelector);
  348. aw.addButton ("Next", 1, KeyPress (KeyPress::returnKey));
  349. aw.addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey));
  350. for (;;)
  351. {
  352. if (aw.runModalLoop() == 0)
  353. return 0;
  354. if (FileHelpers::isJuceFolder (juceFolderSelector.getCurrentFile()))
  355. {
  356. wizard = createWizard (aw.getComboBoxComponent ("type")->getSelectedItemIndex());
  357. break;
  358. }
  359. aw.setColour (AlertWindow::textColourId, Colours::red);
  360. aw.setMessage ("Please select a valid Juce folder for the project to use!");
  361. }
  362. }
  363. return wizard != nullptr ? wizard->runWizard (ownerWindow) : 0;
  364. }