2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-10 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "jucer_NewProjectWizard.h"
29 //==============================================================================
30 class GUIAppWizard
: public NewProjectWizard
36 const String
getName() { return "GUI Application"; }
37 const String
getDescription() { return "Creates a standard application"; }
39 void addItemsToAlertWindow (AlertWindow
& aw
)
41 const char* fileOptions
[] = { "Create a Main.cpp file",
42 "Create a Main.cpp file and a basic window",
43 "Don't create any files", 0 };
45 aw
.addComboBox ("files", StringArray (fileOptions
), "Files to Auto-Generate");
48 const String
processResultsFromAlertWindow (AlertWindow
& aw
)
50 createMainCpp
= createWindow
= false;
52 switch (aw
.getComboBoxComponent ("files")->getSelectedItemIndex())
54 case 0: createMainCpp
= true; break;
55 case 1: createMainCpp
= createWindow
= true; break;
57 default: jassertfalse
; break;
63 bool initialiseProject (Project
& project
)
65 if (! getSourceFilesFolder().createDirectory())
66 failedFiles
.add (getSourceFilesFolder().getFullPathName());
68 File mainCppFile
= getSourceFilesFolder().getChildFile ("Main.cpp");
69 File mainWindowCpp
= getSourceFilesFolder().getChildFile ("MainWindow.cpp");
70 File mainWindowH
= mainWindowCpp
.withFileExtension (".h");
71 String windowClassName
= "MainAppWindow";
73 project
.getProjectType() = Project::application
;
75 Project::Item
group (project
.createNewGroup());
76 project
.getMainGroup().addChild (group
, 0);
77 group
.getName() = "Source";
79 for (int i
= project
.getNumConfigurations(); --i
>= 0;)
80 project
.getConfiguration(i
).getTargetBinaryName() = File::createLegalFileName (appTitle
);
82 String
appHeaders (CodeHelpers::createIncludeStatement (project
.getAppIncludeFile(), mainCppFile
));
83 String initCode
, shutdownCode
, anotherInstanceStartedCode
, privateMembers
, memberInitialisers
;
87 appHeaders
<< newLine
<< CodeHelpers::createIncludeStatement (mainWindowH
, mainCppFile
);
88 initCode
= "mainWindow = new " + windowClassName
+ "();";
89 shutdownCode
= "mainWindow = 0;";
90 privateMembers
= "ScopedPointer <" + windowClassName
+ "> mainWindow;";
92 String windowH
= project
.getFileTemplate ("jucer_WindowTemplate_h")
93 .replace ("INCLUDES", CodeHelpers::createIncludeStatement (project
.getAppIncludeFile(), mainWindowH
), false)
94 .replace ("WINDOWCLASS", windowClassName
, false)
95 .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (mainWindowH
), false);
97 String windowCpp
= project
.getFileTemplate ("jucer_WindowTemplate_cpp")
98 .replace ("INCLUDES", CodeHelpers::createIncludeStatement (mainWindowH
, mainWindowCpp
), false)
99 .replace ("WINDOWCLASS", windowClassName
, false);
101 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainWindowH
, windowH
))
102 failedFiles
.add (mainWindowH
.getFullPathName());
104 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainWindowCpp
, windowCpp
))
105 failedFiles
.add (mainWindowCpp
.getFullPathName());
107 group
.addFile (mainWindowCpp
, -1);
108 group
.addFile (mainWindowH
, -1);
113 String mainCpp
= project
.getFileTemplate ("jucer_MainTemplate_cpp")
114 .replace ("APPHEADERS", appHeaders
, false)
115 .replace ("APPCLASSNAME", CodeHelpers::makeValidIdentifier (appTitle
+ "Application", false, true, false), false)
116 .replace ("MEMBERINITIALISERS", memberInitialisers
, false)
117 .replace ("APPINITCODE", initCode
, false)
118 .replace ("APPSHUTDOWNCODE", shutdownCode
, false)
119 .replace ("APPNAME", CodeHelpers::addEscapeChars (appTitle
), false)
120 .replace ("APPVERSION", "1.0", false)
121 .replace ("ALLOWMORETHANONEINSTANCE", "true", false)
122 .replace ("ANOTHERINSTANCECODE", anotherInstanceStartedCode
, false)
123 .replace ("PRIVATEMEMBERS", privateMembers
, false);
125 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile
, mainCpp
))
126 failedFiles
.add (mainCppFile
.getFullPathName());
128 group
.addFile (mainCppFile
, -1);
135 bool createMainCpp
, createWindow
;
138 //==============================================================================
139 class ConsoleAppWizard
: public NewProjectWizard
142 ConsoleAppWizard() {}
143 ~ConsoleAppWizard() {}
145 const String
getName() { return "Console Application"; }
146 const String
getDescription() { return "Creates a command-line application with no GUI features"; }
148 void addItemsToAlertWindow (AlertWindow
& aw
)
150 const char* fileOptions
[] = { "Create a Main.cpp file",
151 "Don't create any files", 0 };
153 aw
.addComboBox ("files", StringArray (fileOptions
), "Files to Auto-Generate");
156 const String
processResultsFromAlertWindow (AlertWindow
& aw
)
158 createMainCpp
= false;
160 switch (aw
.getComboBoxComponent ("files")->getSelectedItemIndex())
162 case 0: createMainCpp
= true; break;
164 default: jassertfalse
; break;
167 return String::empty
;
170 bool initialiseProject (Project
& project
)
172 if (! getSourceFilesFolder().createDirectory())
173 failedFiles
.add (getSourceFilesFolder().getFullPathName());
175 File mainCppFile
= getSourceFilesFolder().getChildFile ("Main.cpp");
177 project
.getProjectType() = Project::commandLineApp
;
179 Project::Item
group (project
.createNewGroup());
180 project
.getMainGroup().addChild (group
, 0);
181 group
.getName() = "Source";
183 for (int i
= project
.getNumConfigurations(); --i
>= 0;)
184 project
.getConfiguration(i
).getTargetBinaryName() = File::createLegalFileName (appTitle
);
188 String
appHeaders (CodeHelpers::createIncludeStatement (project
.getAppIncludeFile(), mainCppFile
));
190 String mainCpp
= project
.getFileTemplate ("jucer_MainConsoleAppTemplate_cpp")
191 .replace ("APPHEADERS", appHeaders
, false);
193 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile
, mainCpp
))
194 failedFiles
.add (mainCppFile
.getFullPathName());
196 group
.addFile (mainCppFile
, -1);
206 //==============================================================================
207 class AudioPluginAppWizard
: public NewProjectWizard
210 AudioPluginAppWizard() {}
211 ~AudioPluginAppWizard() {}
213 const String
getName() { return "Audio Plug-In"; }
214 const String
getDescription() { return "Creates an audio plugin project"; }
216 void addItemsToAlertWindow (AlertWindow
& aw
)
220 const String
processResultsFromAlertWindow (AlertWindow
& aw
)
222 return String::empty
;
225 bool initialiseProject (Project
& project
)
227 if (! getSourceFilesFolder().createDirectory())
228 failedFiles
.add (getSourceFilesFolder().getFullPathName());
230 String filterClassName
= CodeHelpers::makeValidIdentifier (appTitle
, true, true, false) + "AudioProcessor";
231 filterClassName
= filterClassName
.substring (0, 1).toUpperCase() + filterClassName
.substring (1);
232 String editorClassName
= filterClassName
+ "Editor";
234 File filterCppFile
= getSourceFilesFolder().getChildFile ("PluginProcessor.cpp");
235 File filterHFile
= filterCppFile
.withFileExtension (".h");
236 File editorCppFile
= getSourceFilesFolder().getChildFile ("PluginEditor.cpp");
237 File editorHFile
= editorCppFile
.withFileExtension (".h");
239 project
.getProjectType() = Project::audioPlugin
;
241 Project::Item
group (project
.createNewGroup());
242 project
.getMainGroup().addChild (group
, 0);
243 group
.getName() = "Source";
244 project
.getJuceConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled
; // disabled because it interferes with RTAS build on PC
246 for (int i
= project
.getNumConfigurations(); --i
>= 0;)
247 project
.getConfiguration(i
).getTargetBinaryName() = File::createLegalFileName (appTitle
);
249 String
appHeaders (CodeHelpers::createIncludeStatement (project
.getAppIncludeFile(), filterCppFile
));
250 appHeaders
<< newLine
<< CodeHelpers::createIncludeStatement (project
.getPluginCharacteristicsFile(), filterCppFile
);
252 String filterCpp
= project
.getFileTemplate ("jucer_AudioPluginFilterTemplate_cpp")
253 .replace ("FILTERHEADERS", CodeHelpers::createIncludeStatement (filterHFile
, filterCppFile
)
254 + newLine
+ CodeHelpers::createIncludeStatement (editorHFile
, filterCppFile
), false)
255 .replace ("FILTERCLASSNAME", filterClassName
, false)
256 .replace ("EDITORCLASSNAME", editorClassName
, false);
258 String filterH
= project
.getFileTemplate ("jucer_AudioPluginFilterTemplate_h")
259 .replace ("APPHEADERS", appHeaders
, false)
260 .replace ("FILTERCLASSNAME", filterClassName
, false)
261 .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (filterHFile
), false);
263 String editorCpp
= project
.getFileTemplate ("jucer_AudioPluginEditorTemplate_cpp")
264 .replace ("EDITORCPPHEADERS", CodeHelpers::createIncludeStatement (filterHFile
, filterCppFile
)
265 + newLine
+ CodeHelpers::createIncludeStatement (editorHFile
, filterCppFile
), false)
266 .replace ("FILTERCLASSNAME", filterClassName
, false)
267 .replace ("EDITORCLASSNAME", editorClassName
, false);
269 String editorH
= project
.getFileTemplate ("jucer_AudioPluginEditorTemplate_h")
270 .replace ("EDITORHEADERS", appHeaders
+ newLine
+ CodeHelpers::createIncludeStatement (filterHFile
, filterCppFile
), false)
271 .replace ("FILTERCLASSNAME", filterClassName
, false)
272 .replace ("EDITORCLASSNAME", editorClassName
, false)
273 .replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (editorHFile
), false);
275 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterCppFile
, filterCpp
))
276 failedFiles
.add (filterCppFile
.getFullPathName());
278 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (filterHFile
, filterH
))
279 failedFiles
.add (filterHFile
.getFullPathName());
281 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorCppFile
, editorCpp
))
282 failedFiles
.add (editorCppFile
.getFullPathName());
284 if (! FileHelpers::overwriteFileWithNewDataIfDifferent (editorHFile
, editorH
))
285 failedFiles
.add (editorHFile
.getFullPathName());
287 group
.addFile (filterCppFile
, -1);
288 group
.addFile (filterHFile
, -1);
289 group
.addFile (editorCppFile
, -1);
290 group
.addFile (editorHFile
, -1);
296 //==============================================================================
297 /*class BrowserPluginAppWizard : public NewProjectWizard
300 BrowserPluginAppWizard() {}
301 ~BrowserPluginAppWizard() {}
303 const String getName() { return "Browser Plug-In"; }
304 const String getDescription() { return "Creates an audio plugin project"; }
306 void addItemsToAlertWindow (AlertWindow& aw)
310 const String processResultsFromAlertWindow (AlertWindow& aw)
312 return String::empty;
315 bool initialiseProject (Project& project)
321 //==============================================================================
322 //==============================================================================
323 NewProjectWizard::NewProjectWizard()
327 NewProjectWizard::~NewProjectWizard()
331 const StringArray
NewProjectWizard::getWizards()
335 for (int i
= 0; i
< getNumWizards(); ++i
)
337 ScopedPointer
<NewProjectWizard
> wiz (createWizard (i
));
338 s
.add (wiz
->getName());
344 int NewProjectWizard::getNumWizards()
349 NewProjectWizard
* NewProjectWizard::createWizard (int index
)
353 case 0: return new GUIAppWizard();
354 case 1: return new ConsoleAppWizard();
355 case 2: return new AudioPluginAppWizard();
356 //case 3: return new BrowserPluginAppWizard();
357 default: jassertfalse
; break;
363 //==============================================================================
364 Project
* NewProjectWizard::runWizard (Component
* ownerWindow_
)
366 ownerWindow
= ownerWindow_
;
369 static File newProjectFolder
;
370 FileChooser
fc ("New Juce Project", newProjectFolder
, "*");
372 if (! fc
.browseForDirectory())
375 targetFolder
= newProjectFolder
= fc
.getResult();
377 if (! newProjectFolder
.exists())
379 if (! newProjectFolder
.createDirectory())
380 failedFiles
.add (newProjectFolder
.getFullPathName());
383 if (FileHelpers::containsAnyNonHiddenFiles (newProjectFolder
))
385 if (! AlertWindow::showOkCancelBox (AlertWindow::InfoIcon
, "New Juce Project",
386 "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."))
391 if (failedFiles
.size() == 0)
393 AlertWindow
aw ("New " + getName(),
394 "Please choose some basic project options...",
395 AlertWindow::NoIcon
, ownerWindow
);
397 aw
.addTextEditor ("name", "", "Project Name", false);
399 addItemsToAlertWindow (aw
);
401 aw
.addButton ("Create Project", 1, KeyPress (KeyPress::returnKey
));
402 aw
.addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey
));
406 if (aw
.runModalLoop() == 0)
409 appTitle
= aw
.getTextEditorContents ("name").trim();
411 String
error (processResultsFromAlertWindow (aw
));
413 if (error
.isEmpty() && appTitle
.isEmpty())
414 error
= "Please enter a sensible project title!";
419 aw
.setColour (AlertWindow::textColourId
, Colours::red
);
420 aw
.setMessage (error
);
424 projectFile
= targetFolder
.getChildFile (File::createLegalFileName (appTitle
))
425 .withFileExtension (Project::projectFileExtension
);
427 ScopedPointer
<Project
> project (new Project (projectFile
));
429 if (failedFiles
.size() == 0)
431 project
->setFile (projectFile
);
432 project
->setTitle (appTitle
);
433 project
->setBundleIdentifierToDefault();
435 if (! initialiseProject (*project
))
438 if (project
->save (false, true) != FileBasedDocument::savedOk
)
441 project
->setChangedFlag (false);
444 if (failedFiles
.size() > 0)
446 AlertWindow::showMessageBox (AlertWindow::WarningIcon
,
447 "Errors in Creating Project!",
448 "The following files couldn't be written:\n\n"
449 + failedFiles
.joinIntoString ("\n", 0, 10));
453 return project
.release();
456 Project
* NewProjectWizard::runNewProjectWizard (Component
* ownerWindow
)
458 ScopedPointer
<NewProjectWizard
> wizard
;
461 AlertWindow
aw ("New Juce Project",
462 "Select the type of project to create, and the location of your Juce folder",
466 aw
.addComboBox ("type", getWizards(), "Project Type");
468 FilenameComponent
juceFolderSelector ("Juce Library Location", StoredSettings::getInstance()->getLastKnownJuceFolder(),
469 true, true, false, "*", String::empty
, "(Please select the folder containing Juce!)");
470 juceFolderSelector
.setSize (350, 22);
472 aw
.addCustomComponent (&juceFolderSelector
);
474 aw
.addButton ("Next", 1, KeyPress (KeyPress::returnKey
));
475 aw
.addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey
));
479 if (aw
.runModalLoop() == 0)
482 if (FileHelpers::isJuceFolder (juceFolderSelector
.getCurrentFile()))
484 wizard
= createWizard (aw
.getComboBoxComponent ("type")->getSelectedItemIndex());
488 aw
.setColour (AlertWindow::textColourId
, Colours::red
);
489 aw
.setMessage ("Please select a valid Juce folder for the project to use!");
493 return wizard
!= nullptr ? wizard
->runWizard (ownerWindow
) : 0;