Browse Source

Introjucer updates to the new project wizard and module update system.

tags/2021-05-28
jules 14 years ago
parent
commit
c7354b927e
21 changed files with 581 additions and 366 deletions
  1. +89
    -42
      extras/Introjucer/Source/Application/jucer_Application.h
  2. +2
    -1
      extras/Introjucer/Source/Application/jucer_CommandIDs.h
  3. +1
    -1
      extras/Introjucer/Source/Application/jucer_CommandLine.cpp
  4. +14
    -8
      extras/Introjucer/Source/Application/jucer_JuceUpdater.cpp
  5. +3
    -3
      extras/Introjucer/Source/Application/jucer_JuceUpdater.h
  6. +34
    -18
      extras/Introjucer/Source/Application/jucer_MainWindow.cpp
  7. +4
    -0
      extras/Introjucer/Source/Application/jucer_MainWindow.h
  8. +2
    -1
      extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp
  9. +2
    -1
      extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h
  10. +58
    -15
      extras/Introjucer/Source/Project/jucer_Module.cpp
  11. +8
    -1
      extras/Introjucer/Source/Project/jucer_Module.h
  12. +204
    -116
      extras/Introjucer/Source/Project/jucer_NewProjectWizard.cpp
  13. +10
    -4
      extras/Introjucer/Source/Project/jucer_NewProjectWizard.h
  14. +25
    -19
      extras/Introjucer/Source/Project/jucer_Project.cpp
  15. +2
    -1
      extras/Introjucer/Source/Project/jucer_Project.h
  16. +117
    -70
      extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.cpp
  17. +0
    -43
      extras/Introjucer/Source/Utility/jucer_FileHelpers.cpp
  18. +0
    -6
      extras/Introjucer/Source/Utility/jucer_FileHelpers.h
  19. +3
    -11
      extras/Introjucer/Source/Utility/jucer_MiscUtilities.cpp
  20. +0
    -2
      extras/Introjucer/Source/Utility/jucer_MiscUtilities.h
  21. +3
    -3
      extras/Introjucer/Source/Utility/jucer_StoredSettings.cpp

+ 89
- 42
extras/Introjucer/Source/Application/jucer_Application.h View File

@@ -29,7 +29,6 @@
#include "../jucer_Headers.h" #include "../jucer_Headers.h"
#include "jucer_MainWindow.h" #include "jucer_MainWindow.h"
#include "jucer_JuceUpdater.h" #include "jucer_JuceUpdater.h"
#include "../Project/jucer_NewProjectWizard.h"
#include "jucer_CommandLine.h" #include "jucer_CommandLine.h"
@@ -38,10 +37,7 @@ class JucerApplication : public JUCEApplication
{ {
public: public:
//============================================================================== //==============================================================================
JucerApplication()
{
}
JucerApplication() {}
~JucerApplication() {} ~JucerApplication() {}
//============================================================================== //==============================================================================
@@ -80,6 +76,8 @@ public:
openFile (projects.getReference(i)); openFile (projects.getReference(i));
} }
makeSureUserHasSelectedModuleFolder();
if (mainWindows.size() == 0) if (mainWindows.size() == 0)
createNewMainWindow()->makeVisible(); createNewMainWindow()->makeVisible();
@@ -127,10 +125,10 @@ public:
jassert (mainWindows.contains (w)); jassert (mainWindows.contains (w));
mainWindows.removeObject (w); mainWindows.removeObject (w);
#if ! JUCE_MAC
#if ! JUCE_MAC
if (mainWindows.size() == 0) if (mainWindows.size() == 0)
systemRequestedQuit(); systemRequestedQuit();
#endif
#endif
updateRecentProjectList(); updateRecentProjectList();
} }
@@ -162,6 +160,11 @@ public:
virtual void doExtraInitialisation() {} virtual void doExtraInitialisation() {}
static JucerApplication* getApp()
{
return dynamic_cast<JucerApplication*> (JUCEApplication::getInstance());
}
//============================================================================== //==============================================================================
class MainMenuModel : public MenuBarModel class MainMenuModel : public MenuBarModel
{ {
@@ -173,7 +176,7 @@ public:
const StringArray getMenuBarNames() const StringArray getMenuBarNames()
{ {
const char* const names[] = { "File", "Edit", "View", "Window", "Update", 0 };
const char* const names[] = { "File", "Edit", "View", "Window", "Tools", 0 };
return StringArray ((const char**) names); return StringArray ((const char**) names);
} }
@@ -264,9 +267,10 @@ public:
menu.addSeparator(); menu.addSeparator();
menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments); menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
} }
else if (topLevelMenuIndex == 4) // "Juce" menu
else if (topLevelMenuIndex == 4) // "Tools" menu
{ {
menu.addCommandItem (commandManager, CommandIDs::showJuceVersion);
menu.addCommandItem (commandManager, CommandIDs::updateModules);
menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool);
} }
return menu; return menu;
@@ -288,14 +292,9 @@ public:
MainWindow* w = getApp()->getOrCreateFrontmostWindow(); MainWindow* w = getApp()->getOrCreateFrontmostWindow();
w->makeVisible(); w->makeVisible();
w->getProjectContentComponent()->showDocument (doc); w->getProjectContentComponent()->showDocument (doc);
getApp()->avoidSuperimposedWindows (w);
} }
} }
private:
JucerApplication* getApp() const
{
return static_cast<JucerApplication*> (JUCEApplication::getInstance());
}
}; };
//============================================================================== //==============================================================================
@@ -308,7 +307,8 @@ public:
CommandIDs::showPrefs, CommandIDs::showPrefs,
CommandIDs::closeAllDocuments, CommandIDs::closeAllDocuments,
CommandIDs::saveAll, CommandIDs::saveAll,
CommandIDs::showJuceVersion };
CommandIDs::updateModules,
CommandIDs::showUTF8Tool };
commands.addArray (ids, numElementsInArray (ids)); commands.addArray (ids, numElementsInArray (ids));
} }
@@ -342,8 +342,12 @@ public:
result.setActive (OpenDocumentManager::getInstance()->anyFilesNeedSaving()); result.setActive (OpenDocumentManager::getInstance()->anyFilesNeedSaving());
break; break;
case CommandIDs::showJuceVersion:
result.setInfo ("Download the latest JUCE version", "Checks online for any Juce updates", CommandCategories::general, 0);
case CommandIDs::updateModules:
result.setInfo ("Download the latest JUCE modules", "Checks online for any JUCE modules updates and installs them", CommandCategories::general, 0);
break;
case CommandIDs::showUTF8Tool:
result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0);
break; break;
default: default:
@@ -361,12 +365,9 @@ public:
case CommandIDs::showPrefs: showPrefsPanel(); break; case CommandIDs::showPrefs: showPrefsPanel(); break;
case CommandIDs::saveAll: OpenDocumentManager::getInstance()->saveAll(); break; case CommandIDs::saveAll: OpenDocumentManager::getInstance()->saveAll(); break;
case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
case CommandIDs::showJuceVersion:
{
ModuleList list (ModuleList::getDefaultModulesFolder (nullptr));
JuceUpdater::show (list, mainWindows[0]);
break;
}
case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
case CommandIDs::updateModules: runModuleUpdate (String::empty); break;
default: return JUCEApplication::perform (info); default: return JUCEApplication::perform (info);
} }
@@ -381,17 +382,11 @@ public:
void createNewProject() void createNewProject()
{ {
MainWindow* mw = createNewMainWindow();
ScopedPointer <Project> newProj (NewProjectWizard::runNewProjectWizard (mw));
if (newProj != nullptr)
{
mw->setProject (newProj.release());
mw->makeVisible();
}
else
if (makeSureUserHasSelectedModuleFolder())
{ {
closeWindow (mw);
MainWindow* mw = getOrCreateEmptyWindow();
mw->showNewProjectWizard();
avoidSuperimposedWindows (mw);
} }
} }
@@ -424,6 +419,7 @@ public:
MainWindow* w = getOrCreateEmptyWindow(); MainWindow* w = getOrCreateEmptyWindow();
w->setProject (newDoc.release()); w->setProject (newDoc.release());
w->makeVisible(); w->makeVisible();
avoidSuperimposedWindows (w);
return true; return true;
} }
} }
@@ -433,6 +429,7 @@ public:
const bool ok = w->openFile (file); const bool ok = w->openFile (file);
w->makeVisible(); w->makeVisible();
avoidSuperimposedWindows (w);
return ok; return ok;
} }
@@ -470,6 +467,35 @@ public:
StoredSettings::getInstance()->setLastProjects (projects); StoredSettings::getInstance()->setLastProjects (projects);
} }
bool makeSureUserHasSelectedModuleFolder()
{
if (! ModuleList::isLocalModulesFolderValid())
{
if (! runModuleUpdate ("Please select a location to store your local set of JUCE modules,\n"
"and download the ones that you'd like to use!"))
{
AlertWindow::showMessageBox (AlertWindow::WarningIcon,
"Introjucer",
"Unless you create a local JUCE folder containing some modules, you'll be unable to save any projects correctly!\n\n"
"Use the option on the 'Tools' menu to set this up!");
return false;
}
}
return true;
}
bool runModuleUpdate (const String& message)
{
ModuleList list;
list.rescan (ModuleList::getDefaultModulesFolder (nullptr));
JuceUpdater::show (list, mainWindows[0], message);
ModuleList::setLocalModulesFolder (list.getModulesFolder());
return ModuleList::isJuceOrModulesFolder (list.getModulesFolder());
}
ScopedPointer<MainMenuModel> menuModel; ScopedPointer<MainMenuModel> menuModel;
private: private:
@@ -478,13 +504,9 @@ private:
MainWindow* createNewMainWindow() MainWindow* createNewMainWindow()
{ {
MainWindow* mw = new MainWindow(); MainWindow* mw = new MainWindow();
for (int i = mainWindows.size(); --i >= 0;)
if (mw->getBounds() == mainWindows.getUnchecked(i)->getBounds())
mw->setBounds (mw->getBounds().translated (20, 20));
mainWindows.add (mw); mainWindows.add (mw);
mw->restoreWindowPosition(); mw->restoreWindowPosition();
avoidSuperimposedWindows (mw);
return mw; return mw;
} }
@@ -518,6 +540,31 @@ private:
return createNewMainWindow(); return createNewMainWindow();
} }
void avoidSuperimposedWindows (MainWindow* const mw)
{
for (int i = mainWindows.size(); --i >= 0;)
{
MainWindow* const other = mainWindows.getUnchecked(i);
const Rectangle<int> b1 (mw->getBounds());
const Rectangle<int> b2 (other->getBounds());
if (mw != other
&& std::abs (b1.getX() - b2.getX()) < 3
&& std::abs (b1.getY() - b2.getY()) < 3
&& std::abs (b1.getRight() - b2.getRight()) < 3
&& std::abs (b1.getBottom() - b2.getBottom()) < 3)
{
int dx = 40, dy = 30;
if (b1.getCentreX() >= mw->getScreenBounds().getCentreX()) dx = -dx;
if (b1.getCentreY() >= mw->getScreenBounds().getCentreY()) dy = -dy;
mw->setBounds (b1.translated (dx, dy));
}
}
}
//============================================================================== //==============================================================================
static bool cancelAnyModalComponents() static bool cancelAnyModalComponents()
{ {
@@ -540,8 +587,8 @@ private:
stopTimer(); stopTimer();
delete this; delete this;
if (JUCEApplication::getInstance() != nullptr)
JUCEApplication::getInstance()->systemRequestedQuit();
if (getApp() != nullptr)
getApp()->systemRequestedQuit();
} }
JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier); JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier);


+ 2
- 1
extras/Introjucer/Source/Application/jucer_CommandIDs.h View File

@@ -40,7 +40,8 @@ namespace CommandIDs
static const int openInIDE = 0x200072; static const int openInIDE = 0x200072;
static const int saveAndOpenInIDE = 0x200073; static const int saveAndOpenInIDE = 0x200073;
static const int showProjectSettings = 0x200074; static const int showProjectSettings = 0x200074;
static const int showJuceVersion = 0x200075;
static const int updateModules = 0x200075;
static const int showUTF8Tool = 0x200076;
static const int saveAll = 0x200080; static const int saveAll = 0x200080;
static const int undo = 0x200090; static const int undo = 0x200090;


+ 1
- 1
extras/Introjucer/Source/Application/jucer_CommandLine.cpp View File

@@ -192,7 +192,7 @@ namespace
int listModules() int listModules()
{ {
std::cout << "Downloading list of available modules..." << std::endl; std::cout << "Downloading list of available modules..." << std::endl;
ModuleList list (File::nonexistent);
ModuleList list;
list.loadFromWebsite(); list.loadFromWebsite();
for (int i = 0; i < list.modules.size(); ++i) for (int i = 0; i < list.modules.size(); ++i)


+ 14
- 8
extras/Introjucer/Source/Application/jucer_JuceUpdater.cpp View File

@@ -29,9 +29,9 @@
//============================================================================== //==============================================================================
JuceUpdater::JuceUpdater (ModuleList& moduleList_)
JuceUpdater::JuceUpdater (ModuleList& moduleList_, const String& message)
: moduleList (moduleList_), : moduleList (moduleList_),
latestList (File::nonexistent),
messageLabel (String::empty, message),
filenameComp ("Juce Folder", ModuleList::getLocalModulesFolder (nullptr), filenameComp ("Juce Folder", ModuleList::getLocalModulesFolder (nullptr),
true, true, false, "*", String::empty, "Select your Juce folder"), true, true, false, "*", String::empty, "Select your Juce folder"),
checkNowButton ("Check for available updates on the JUCE website...", checkNowButton ("Check for available updates on the JUCE website...",
@@ -39,6 +39,9 @@ JuceUpdater::JuceUpdater (ModuleList& moduleList_)
installButton ("Download and install selected modules..."), installButton ("Download and install selected modules..."),
selectAllButton ("Select/Deselect All") selectAllButton ("Select/Deselect All")
{ {
messageLabel.setJustificationType (Justification::centred);
addAndMakeVisible (&messageLabel);
addAndMakeVisible (&label); addAndMakeVisible (&label);
addAndMakeVisible (&currentVersionLabel); addAndMakeVisible (&currentVersionLabel);
addAndMakeVisible (&filenameComp); addAndMakeVisible (&filenameComp);
@@ -80,6 +83,7 @@ public:
: DialogWindow ("JUCE Module Updater", : DialogWindow ("JUCE Module Updater",
Colours::lightgrey, true, true) Colours::lightgrey, true, true)
{ {
setUsingNativeTitleBar (true);
setContentOwned (updater, true); setContentOwned (updater, true);
centreAroundComponent (componentToCentreAround, getWidth(), getHeight()); centreAroundComponent (componentToCentreAround, getWidth(), getHeight());
setResizable (true, true); setResizable (true, true);
@@ -94,15 +98,17 @@ private:
JUCE_DECLARE_NON_COPYABLE (UpdateDialogWindow); JUCE_DECLARE_NON_COPYABLE (UpdateDialogWindow);
}; };
void JuceUpdater::show (ModuleList& moduleList, Component* mainWindow)
void JuceUpdater::show (ModuleList& moduleList, Component* mainWindow, const String& message)
{ {
UpdateDialogWindow w (new JuceUpdater (moduleList), mainWindow);
UpdateDialogWindow w (new JuceUpdater (moduleList, message), mainWindow);
w.runModalLoop(); w.runModalLoop();
} }
void JuceUpdater::resized() void JuceUpdater::resized()
{ {
filenameComp.setBounds (20, 40, getWidth() - 40, 22);
messageLabel.setBounds (20, 10, getWidth() - 40, messageLabel.getText().isEmpty() ? 0 : 30);
filenameComp.setBounds (20, messageLabel.getBottom() + 20, getWidth() - 40, 22);
label.setBounds (filenameComp.getX(), filenameComp.getY() - 18, filenameComp.getWidth(), 18); label.setBounds (filenameComp.getX(), filenameComp.getY() - 18, filenameComp.getWidth(), 18);
currentVersionLabel.setBounds (filenameComp.getX(), filenameComp.getBottom(), filenameComp.getWidth(), 25); currentVersionLabel.setBounds (filenameComp.getX(), filenameComp.getBottom(), filenameComp.getWidth(), 25);
checkNowButton.changeWidthToFitText (22); checkNowButton.changeWidthToFitText (22);
@@ -162,7 +168,7 @@ public:
else else
AlertWindow::showMessageBox (AlertWindow::InfoIcon, AlertWindow::showMessageBox (AlertWindow::InfoIcon,
"Module Update", "Module Update",
"Couldn't connect to the website!");
"Couldn't connect to the JUCE webserver!");
} }
void handleAsyncUpdate() void handleAsyncUpdate()
@@ -224,7 +230,7 @@ void JuceUpdater::filenameComponentChanged (FilenameComponent*)
moduleList.rescan (filenameComp.getCurrentFile()); moduleList.rescan (filenameComp.getCurrentFile());
filenameComp.setCurrentFile (moduleList.getModulesFolder(), true, false); filenameComp.setCurrentFile (moduleList.getModulesFolder(), true, false);
if (! FileHelpers::isModulesFolder (moduleList.getModulesFolder()))
if (! ModuleList::isModulesFolder (moduleList.getModulesFolder()))
currentVersionLabel.setText ("(Not a Juce folder)", false); currentVersionLabel.setText ("(Not a Juce folder)", false);
else else
currentVersionLabel.setText (String::empty, false); currentVersionLabel.setText (String::empty, false);
@@ -296,7 +302,7 @@ Component* JuceUpdater::refreshComponentForRow (int rowNumber, bool isRowSelecte
} }
else else
{ {
status << " (latest version already installed)";
status << " (latest version already installed: " << existingModule->version << ")";
toggle.setEnabled (false); toggle.setEnabled (false);
} }
} }


+ 3
- 3
extras/Introjucer/Source/Application/jucer_JuceUpdater.h View File

@@ -37,10 +37,10 @@ class JuceUpdater : public Component,
private ValueTree::Listener private ValueTree::Listener
{ {
public: public:
JuceUpdater (ModuleList& moduleList);
JuceUpdater (ModuleList& moduleList, const String& message);
~JuceUpdater(); ~JuceUpdater();
static void show (ModuleList& moduleList, Component* mainWindow);
static void show (ModuleList& moduleList, Component* mainWindow, const String& message);
//============================================================================== //==============================================================================
void resized(); void resized();
@@ -58,7 +58,7 @@ private:
ModuleList& moduleList; ModuleList& moduleList;
ModuleList latestList; ModuleList latestList;
Label label, currentVersionLabel;
Label messageLabel, label, currentVersionLabel;
FilenameComponent filenameComp; FilenameComponent filenameComp;
TextButton checkNowButton; TextButton checkNowButton;
ListBox availableVersionsList; ListBox availableVersionsList;


+ 34
- 18
extras/Introjucer/Source/Application/jucer_MainWindow.cpp View File

@@ -35,43 +35,42 @@ ScopedPointer<ApplicationCommandManager> commandManager;
//============================================================================== //==============================================================================
MainWindow::MainWindow() MainWindow::MainWindow()
: DocumentWindow (JUCEApplication::getInstance()->getApplicationName(),
: DocumentWindow (JucerApplication::getApp()->getApplicationName(),
Colour::greyLevel (0.6f), Colour::greyLevel (0.6f),
DocumentWindow::allButtons, DocumentWindow::allButtons,
false) false)
{ {
setUsingNativeTitleBar (true); setUsingNativeTitleBar (true);
setContentOwned (new ProjectContentComponent(), false);
createProjectContentCompIfNeeded();
#if ! JUCE_MAC #if ! JUCE_MAC
JucerApplication* app = static_cast<JucerApplication*> (JUCEApplication::getInstance());
setMenuBar (app->menuModel);
setMenuBar (JucerApplication::getApp()->menuModel);
#endif #endif
setResizable (true, false); setResizable (true, false);
centreWithSize (700, 600);
centreWithSize (800, 600);
// Register all the app commands.. // Register all the app commands..
{ {
commandManager->registerAllCommandsForTarget (this); commandManager->registerAllCommandsForTarget (this);
commandManager->registerAllCommandsForTarget (getProjectContentComponent());
// use some temporary objects to harvest their commands.. // use some temporary objects to harvest their commands..
DocumentEditorComponent dec (nullptr); DocumentEditorComponent dec (nullptr);
commandManager->registerAllCommandsForTarget (&dec); commandManager->registerAllCommandsForTarget (&dec);
ProjectContentComponent pcc;
commandManager->registerAllCommandsForTarget (&pcc);
} }
commandManager->getKeyMappings()->resetToDefaultMappings();
// update key mappings..
{
commandManager->getKeyMappings()->resetToDefaultMappings();
ScopedPointer <XmlElement> keys (StoredSettings::getInstance()->getProps().getXmlValue ("keyMappings"));
ScopedPointer <XmlElement> keys (StoredSettings::getInstance()->getProps().getXmlValue ("keyMappings"));
if (keys != nullptr)
commandManager->getKeyMappings()->restoreFromXml (*keys);
if (keys != nullptr)
commandManager->getKeyMappings()->restoreFromXml (*keys);
addKeyListener (commandManager->getKeyMappings());
addKeyListener (commandManager->getKeyMappings());
}
// don't want the window to take focus when the title-bar is clicked.. // don't want the window to take focus when the title-bar is clicked..
setWantsKeyboardFocus (false); setWantsKeyboardFocus (false);
@@ -96,6 +95,15 @@ MainWindow::~MainWindow()
currentProject = nullptr; currentProject = nullptr;
} }
void MainWindow::createProjectContentCompIfNeeded()
{
if (getProjectContentComponent() == nullptr)
{
clearContentComponent();
setContentOwned (new ProjectContentComponent(), false);
}
}
void MainWindow::makeVisible() void MainWindow::makeVisible()
{ {
setVisible (true); setVisible (true);
@@ -115,8 +123,7 @@ void MainWindow::closeButtonPressed()
if (! closeCurrentProject()) if (! closeCurrentProject())
return; return;
JucerApplication* jucer = static_cast<JucerApplication*> (JUCEApplication::getInstance());
jucer->closeWindow (this);
JucerApplication::getApp()->closeWindow (this);
} }
bool MainWindow::closeProject (Project* project) bool MainWindow::closeProject (Project* project)
@@ -150,6 +157,7 @@ bool MainWindow::closeCurrentProject()
void MainWindow::setProject (Project* newProject) void MainWindow::setProject (Project* newProject)
{ {
createProjectContentCompIfNeeded();
getProjectContentComponent()->setProject (newProject); getProjectContentComponent()->setProject (newProject);
currentProject = newProject; currentProject = newProject;
commandManager->commandStatusChanged(); commandManager->commandStatusChanged();
@@ -157,7 +165,7 @@ void MainWindow::setProject (Project* newProject)
// (mustn't do this when the project is 0, because that'll happen on shutdown, // (mustn't do this when the project is 0, because that'll happen on shutdown,
// which will erase the list of recent projects) // which will erase the list of recent projects)
if (newProject != nullptr) if (newProject != nullptr)
static_cast<JucerApplication*> (JUCEApplication::getInstance())->updateRecentProjectList();
JucerApplication::getApp()->updateRecentProjectList();
} }
void MainWindow::restoreWindowPosition() void MainWindow::restoreWindowPosition()
@@ -181,6 +189,8 @@ bool MainWindow::canOpenFile (const File& file) const
bool MainWindow::openFile (const File& file) bool MainWindow::openFile (const File& file)
{ {
createProjectContentCompIfNeeded();
if (file.hasFileExtension (Project::projectFileExtension)) if (file.hasFileExtension (Project::projectFileExtension))
{ {
ScopedPointer <Project> newDoc (new Project (file)); ScopedPointer <Project> newDoc (new Project (file));
@@ -232,7 +242,7 @@ void MainWindow::activeWindowStatusChanged()
void MainWindow::updateTitle (const String& documentName) void MainWindow::updateTitle (const String& documentName)
{ {
String name (JUCEApplication::getInstance()->getApplicationName());
String name (JucerApplication::getApp()->getApplicationName());
if (currentProject != nullptr) if (currentProject != nullptr)
name = currentProject->getDocumentTitle() + " - " + name; name = currentProject->getDocumentTitle() + " - " + name;
@@ -243,6 +253,12 @@ void MainWindow::updateTitle (const String& documentName)
setName (name); setName (name);
} }
void MainWindow::showNewProjectWizard()
{
jassert (currentProject == nullptr);
setContentOwned (NewProjectWizard::createComponent(), true);
makeVisible();
}
//============================================================================== //==============================================================================
ApplicationCommandTarget* MainWindow::getNextCommandTarget() ApplicationCommandTarget* MainWindow::getNextCommandTarget()


+ 4
- 0
extras/Introjucer/Source/Application/jucer_MainWindow.h View File

@@ -57,6 +57,8 @@ public:
bool closeProject (Project* project); bool closeProject (Project* project);
bool closeCurrentProject(); bool closeCurrentProject();
void showNewProjectWizard();
bool isInterestedInFileDrag (const StringArray& files); bool isInterestedInFileDrag (const StringArray& files);
void filesDropped (const StringArray& filenames, int mouseX, int mouseY); void filesDropped (const StringArray& filenames, int mouseX, int mouseY);
@@ -84,6 +86,8 @@ private:
return "projectWindowPos_" + currentProject->getProjectUID(); return "projectWindowPos_" + currentProject->getProjectUID();
} }
void createProjectContentCompIfNeeded();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow);
}; };


+ 2
- 1
extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp View File

@@ -209,7 +209,8 @@ void ProjectExporter::createPropertyEditors (Array <PropertyComponent*>& props)
props.getLast()->setTooltip ("The location of the Juce library folder that the " + name + " project will use to when compiling. This can be an absolute path, or relative to the jucer project folder, but it must be valid on the filesystem of the machine you use to actually do the compiling."); props.getLast()->setTooltip ("The location of the Juce library folder that the " + name + " project will use to when compiling. This can be an absolute path, or relative to the jucer project folder, but it must be valid on the filesystem of the machine you use to actually do the compiling.");
OwnedArray<LibraryModule> modules; OwnedArray<LibraryModule> modules;
ModuleList moduleList (ModuleList::getDefaultModulesFolder (&project));
ModuleList moduleList;
moduleList.rescan (ModuleList::getDefaultModulesFolder (&project));
project.createRequiredModules (moduleList, modules); project.createRequiredModules (moduleList, modules);
for (int i = 0; i < modules.size(); ++i) for (int i = 0; i < modules.size(); ++i)
modules.getUnchecked(i)->createPropertyEditors (*this, props); modules.getUnchecked(i)->createPropertyEditors (*this, props);


+ 2
- 1
extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h View File

@@ -61,7 +61,8 @@ public:
OwnedArray<LibraryModule> modules; OwnedArray<LibraryModule> modules;
{ {
ModuleList moduleList (ModuleList::getDefaultModulesFolder (&project));
ModuleList moduleList;
moduleList.rescan (ModuleList::getDefaultModulesFolder (&project));
project.createRequiredModules (moduleList, modules); project.createRequiredModules (moduleList, modules);
} }


+ 58
- 15
extras/Introjucer/Source/Project/jucer_Module.cpp View File

@@ -31,9 +31,8 @@
//============================================================================== //==============================================================================
ModuleList::ModuleList (const File& modulesFolder_)
ModuleList::ModuleList()
{ {
rescan (modulesFolder_);
} }
ModuleList::ModuleList (const ModuleList& other) ModuleList::ModuleList (const ModuleList& other)
@@ -68,6 +67,29 @@ bool ModuleList::operator== (const ModuleList& other) const
return true; return true;
} }
bool ModuleList::isLocalModulesFolderValid()
{
return isModulesFolder (getModulesFolderForJuceOrModulesFolder (getLocalModulesFolder (nullptr)));
}
bool ModuleList::isJuceFolder (const File& folder)
{
return folder.getFileName().containsIgnoreCase ("juce")
&& isModulesFolder (folder.getChildFile ("modules"));
}
bool ModuleList::isModulesFolder (const File& folder)
{
return folder.getFileName().equalsIgnoreCase ("modules")
&& folder.isDirectory();
}
bool ModuleList::isJuceOrModulesFolder (const File& folder)
{
return isJuceFolder (folder) || isModulesFolder (folder);
}
File ModuleList::getModulesFolderForJuceOrModulesFolder (const File& f) File ModuleList::getModulesFolderForJuceOrModulesFolder (const File& f)
{ {
if (f.getFileName() != "modules" && f.isDirectory() && f.getChildFile ("modules").isDirectory()) if (f.getFileName() != "modules" && f.isDirectory() && f.getChildFile ("modules").isDirectory())
@@ -87,12 +109,16 @@ File ModuleList::getDefaultModulesFolder (Project* project)
File f (project->resolveFilename (exp->getJuceFolder().toString())); File f (project->resolveFilename (exp->getJuceFolder().toString()));
f = getModulesFolderForJuceOrModulesFolder (f); f = getModulesFolderForJuceOrModulesFolder (f);
if (FileHelpers::isModulesFolder (f))
if (ModuleList::isModulesFolder (f))
return f; return f;
} }
} }
#if JUCE_WINDOWS
return File::getSpecialLocation (File::userDocumentsDirectory)
#else
return File::getSpecialLocation (File::userHomeDirectory) return File::getSpecialLocation (File::userHomeDirectory)
#endif
.getChildFile ("juce") .getChildFile ("juce")
.getChildFile ("modules"); .getChildFile ("modules");
} }
@@ -104,7 +130,7 @@ File ModuleList::getLocalModulesFolder (Project* project)
File f (StoredSettings::getInstance()->getProps().getValue ("lastJuceFolder", defaultJuceFolder.getFullPathName())); File f (StoredSettings::getInstance()->getProps().getValue ("lastJuceFolder", defaultJuceFolder.getFullPathName()));
f = getModulesFolderForJuceOrModulesFolder (f); f = getModulesFolderForJuceOrModulesFolder (f);
if ((! FileHelpers::isModulesFolder (f)) && FileHelpers::isModulesFolder (defaultJuceFolder))
if ((! ModuleList::isModulesFolder (f)) && ModuleList::isModulesFolder (defaultJuceFolder))
f = defaultJuceFolder; f = defaultJuceFolder;
return f; return f;
@@ -263,17 +289,20 @@ void ModuleList::getDependencies (const String& moduleID, StringArray& dependenc
const var depsArray (m->moduleInfo ["dependencies"]); const var depsArray (m->moduleInfo ["dependencies"]);
const Array<var>* const deps = depsArray.getArray(); const Array<var>* const deps = depsArray.getArray();
for (int i = 0; i < deps->size(); ++i)
if (deps != nullptr)
{ {
const var& d = deps->getReference(i);
for (int i = 0; i < deps->size(); ++i)
{
const var& d = deps->getReference(i);
String uid (d ["id"].toString());
String version (d ["version"].toString());
String uid (d ["id"].toString());
String version (d ["version"].toString());
if (! dependencies.contains (uid, true))
{
dependencies.add (uid);
getDependencies (uid, dependencies);
if (! dependencies.contains (uid, true))
{
dependencies.add (uid);
getDependencies (uid, dependencies);
}
} }
} }
} }
@@ -302,6 +331,18 @@ void ModuleList::createDependencies (const String& moduleID, OwnedArray<LibraryM
} }
} }
StringArray ModuleList::getExtraDependenciesNeeded (Project& project, const ModuleList::Module& m)
{
StringArray dependencies, extraDepsNeeded;
getDependencies (m.uid, dependencies);
for (int i = 0; i < dependencies.size(); ++i)
if ((! project.isModuleEnabled (dependencies[i])) && dependencies[i] != m.uid)
extraDepsNeeded.add (dependencies[i]);
return extraDepsNeeded;
}
//============================================================================== //==============================================================================
LibraryModule::LibraryModule (const File& file) LibraryModule::LibraryModule (const File& file)
: moduleInfo (JSON::parse (file)), : moduleInfo (JSON::parse (file)),
@@ -334,9 +375,11 @@ File LibraryModule::getInclude (const File& folder) const
RelativePath LibraryModule::getModuleRelativeToProject (ProjectExporter& exporter) const RelativePath LibraryModule::getModuleRelativeToProject (ProjectExporter& exporter) const
{ {
return RelativePath (exporter.getJuceFolder().toString(), RelativePath::projectFolder)
.getChildFile ("modules")
.getChildFile (getID());
RelativePath p (exporter.getJuceFolder().toString(), RelativePath::projectFolder);
if (p.getFileName() != "modules")
p = p.getChildFile ("modules");
return p.getChildFile (getID());
} }
//============================================================================== //==============================================================================


+ 8
- 1
extras/Introjucer/Source/Project/jucer_Module.h View File

@@ -86,7 +86,7 @@ private:
class ModuleList class ModuleList
{ {
public: public:
ModuleList (const File& modulesFolder);
ModuleList();
ModuleList (const ModuleList&); ModuleList (const ModuleList&);
ModuleList& operator= (const ModuleList&); ModuleList& operator= (const ModuleList&);
@@ -121,13 +121,20 @@ public:
bool operator== (const ModuleList&) const; bool operator== (const ModuleList&) const;
//============================================================================== //==============================================================================
static bool isJuceFolder (const File& folder);
static bool isModulesFolder (const File& folder);
static bool isJuceOrModulesFolder (const File& folder);
static File getDefaultModulesFolder (Project* project); static File getDefaultModulesFolder (Project* project);
static bool isLocalModulesFolderValid();
static File getLocalModulesFolder (Project* project); static File getLocalModulesFolder (Project* project);
static void setLocalModulesFolder (const File& newFile); static void setLocalModulesFolder (const File& newFile);
static File getModulesFolderForJuceOrModulesFolder (const File& f); static File getModulesFolderForJuceOrModulesFolder (const File& f);
StringArray getExtraDependenciesNeeded (Project& project, const Module& m);
//============================================================================== //==============================================================================
OwnedArray<Module> modules; OwnedArray<Module> modules;


+ 204
- 116
extras/Introjucer/Source/Project/jucer_NewProjectWizard.cpp View File

@@ -26,6 +26,31 @@
#include "jucer_NewProjectWizard.h" #include "jucer_NewProjectWizard.h"
#include "jucer_ProjectType.h" #include "jucer_ProjectType.h"
#include "jucer_Module.h" #include "jucer_Module.h"
#include "../Application/jucer_Application.h"
#include "../Application/jucer_MainWindow.h"
static void createFileCreationOptionComboBox (Component& setupComp,
OwnedArray<Component>& itemsCreated,
const char** types)
{
ComboBox* c = new ComboBox();
c->setComponentID ("filesToCreate");
itemsCreated.add (c);
setupComp.addAndMakeVisible (c);
const char* fileOptions[] = { "Create a Main.cpp file",
"Create a Main.cpp file and a basic window",
"Don't create any files", 0 };
c->addItemList (StringArray (fileOptions), 1);
c->setSelectedId (1, false);
Label* l = new Label (String::empty, "Files to Auto-Generate:");
l->attachToComponent (c, true);
itemsCreated.add (l);
c->setBounds ("parent.width / 2 + 160, 10, parent.width - 10, top + 22");
}
//============================================================================== //==============================================================================
class GUIAppWizard : public NewProjectWizard class GUIAppWizard : public NewProjectWizard
@@ -36,20 +61,22 @@ public:
String getName() { return "GUI Application"; } String getName() { return "GUI Application"; }
String getDescription() { return "Creates a standard application"; } String getDescription() { return "Creates a standard application"; }
void addItemsToAlertWindow (AlertWindow& aw)
void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
{ {
const char* fileOptions[] = { "Create a Main.cpp file", const char* fileOptions[] = { "Create a Main.cpp file",
"Create a Main.cpp file and a basic window", "Create a Main.cpp file and a basic window",
"Don't create any files", 0 }; "Don't create any files", 0 };
aw.addComboBox ("files", StringArray (fileOptions), "Files to Auto-Generate");
createFileCreationOptionComboBox (setupComp, itemsCreated, fileOptions);
} }
String processResultsFromAlertWindow (AlertWindow& aw)
Result processResultsFromSetupItems (Component& setupComp)
{ {
ComboBox* cb = dynamic_cast<ComboBox*> (setupComp.findChildWithID ("filesToCreate"));
jassert (cb != nullptr);
createMainCpp = createWindow = false; createMainCpp = createWindow = false;
switch (aw.getComboBoxComponent ("files")->getSelectedItemIndex())
switch (cb->getSelectedItemIndex())
{ {
case 0: createMainCpp = true; break; case 0: createMainCpp = true; break;
case 1: createMainCpp = createWindow = true; break; case 1: createMainCpp = createWindow = true; break;
@@ -57,7 +84,7 @@ public:
default: jassertfalse; break; default: jassertfalse; break;
} }
return String::empty;
return Result::ok();
} }
bool initialiseProject (Project& project) bool initialiseProject (Project& project)
@@ -142,26 +169,29 @@ public:
String getName() { return "Console Application"; } String getName() { return "Console Application"; }
String getDescription() { return "Creates a command-line application with no GUI features"; } String getDescription() { return "Creates a command-line application with no GUI features"; }
void addItemsToAlertWindow (AlertWindow& aw)
void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
{ {
const char* fileOptions[] = { "Create a Main.cpp file", const char* fileOptions[] = { "Create a Main.cpp file",
"Don't create any files", 0 }; "Don't create any files", 0 };
aw.addComboBox ("files", StringArray (fileOptions), "Files to Auto-Generate");
createFileCreationOptionComboBox (setupComp, itemsCreated, fileOptions);
} }
String processResultsFromAlertWindow (AlertWindow& aw)
Result processResultsFromSetupItems (Component& setupComp)
{ {
ComboBox* cb = dynamic_cast<ComboBox*> (setupComp.findChildWithID ("filesToCreate"));
jassert (cb != nullptr);
createMainCpp = false; createMainCpp = false;
switch (aw.getComboBoxComponent ("files")->getSelectedItemIndex())
switch (cb->getSelectedItemIndex())
{ {
case 0: createMainCpp = true; break; case 0: createMainCpp = true; break;
case 1: break; case 1: break;
default: jassertfalse; break; default: jassertfalse; break;
} }
return String::empty;
return Result::ok();
} }
bool initialiseProject (Project& project) bool initialiseProject (Project& project)
@@ -207,13 +237,13 @@ public:
String getName() { return "Audio Plug-In"; } String getName() { return "Audio Plug-In"; }
String getDescription() { return "Creates an audio plugin project"; } String getDescription() { return "Creates an audio plugin project"; }
void addItemsToAlertWindow (AlertWindow& aw)
void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated)
{ {
} }
String processResultsFromAlertWindow (AlertWindow& aw)
Result processResultsFromSetupItems (Component& setupComp)
{ {
return String::empty;
return Result::ok();
} }
bool initialiseProject (Project& project) bool initialiseProject (Project& project)
@@ -231,7 +261,7 @@ public:
File editorHFile = editorCppFile.withFileExtension (".h"); File editorHFile = editorCppFile.withFileExtension (".h");
project.getProjectTypeValue() = ProjectType::getAudioPluginTypeName(); project.getProjectTypeValue() = ProjectType::getAudioPluginTypeName();
project.addModule ("juce_audio_plugin_client");
project.addModule ("juce_audio_plugin_client", true);
Project::Item sourceGroup (project.getMainGroup().addNewSubGroup ("Source", 0)); Project::Item sourceGroup (project.getMainGroup().addNewSubGroup ("Source", 0));
project.getConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled; // disabled because it interferes with RTAS build on PC project.getConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled; // disabled because it interferes with RTAS build on PC
@@ -285,31 +315,6 @@ public:
} }
}; };
//==============================================================================
/*class BrowserPluginAppWizard : public NewProjectWizard
{
public:
BrowserPluginAppWizard() {}
~BrowserPluginAppWizard() {}
String getName() { return "Browser Plug-In"; }
String getDescription() { return "Creates an audio plugin project"; }
void addItemsToAlertWindow (AlertWindow& aw)
{
}
String processResultsFromAlertWindow (AlertWindow& aw)
{
return String::empty;
}
bool initialiseProject (Project& project)
{
return true;
}
};*/
//============================================================================== //==============================================================================
//============================================================================== //==============================================================================
NewProjectWizard::NewProjectWizard() {} NewProjectWizard::NewProjectWizard() {}
@@ -347,71 +352,42 @@ NewProjectWizard* NewProjectWizard::createWizard (int index)
return 0; return 0;
} }
File& NewProjectWizard::getLastWizardFolder()
{
#if JUCE_WINDOWS
static File lastFolder (File::getSpecialLocation (File::userDocumentsDirectory));
#else
static File lastFolder (File::getSpecialLocation (File::userHomeDirectory));
#endif
return lastFolder;
}
//============================================================================== //==============================================================================
Project* NewProjectWizard::runWizard (Component* ownerWindow_)
Project* NewProjectWizard::runWizard (Component* ownerWindow_,
const String& projectName,
const File& targetFolder_)
{ {
ownerWindow = ownerWindow_; ownerWindow = ownerWindow_;
appTitle = projectName;
targetFolder = targetFolder_;
if (! targetFolder.exists())
{ {
static File newProjectFolder;
FileChooser fc ("New Juce Project", newProjectFolder, "*");
if (! fc.browseForDirectory())
return 0;
targetFolder = newProjectFolder = fc.getResult();
if (! newProjectFolder.exists())
{
if (! newProjectFolder.createDirectory())
failedFiles.add (newProjectFolder.getFullPathName());
}
if (FileHelpers::containsAnyNonHiddenFiles (newProjectFolder))
{
if (! AlertWindow::showOkCancelBox (AlertWindow::InfoIcon, "New Juce Project",
"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."))
return 0;
}
if (! targetFolder.createDirectory())
failedFiles.add (targetFolder.getFullPathName());
} }
if (failedFiles.size() == 0)
else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder))
{ {
AlertWindow aw ("New " + getName(),
"Please choose some basic project options...",
AlertWindow::NoIcon, ownerWindow);
aw.addTextEditor ("name", "", "Project Name", false);
addItemsToAlertWindow (aw);
aw.addButton ("Create Project", 1, KeyPress (KeyPress::returnKey));
aw.addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey));
for (;;)
{
if (aw.runModalLoop() == 0)
return 0;
appTitle = aw.getTextEditorContents ("name").trim();
String error (processResultsFromAlertWindow (aw));
if (error.isEmpty() && appTitle.isEmpty())
error = "Please enter a sensible project title!";
if (error.isEmpty())
break;
aw.setColour (AlertWindow::textColourId, Colours::red);
aw.setMessage (error);
}
if (! AlertWindow::showOkCancelBox (AlertWindow::InfoIcon, "New Juce Project",
"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."))
return nullptr;
} }
projectFile = targetFolder.getChildFile (File::createLegalFileName (appTitle)) projectFile = targetFolder.getChildFile (File::createLegalFileName (appTitle))
.withFileExtension (Project::projectFileExtension); .withFileExtension (Project::projectFileExtension);
ScopedPointer<Project> project (new Project (projectFile)); ScopedPointer<Project> project (new Project (projectFile));
project->addDefaultModules (true);
if (failedFiles.size() == 0) if (failedFiles.size() == 0)
{ {
@@ -420,10 +396,10 @@ Project* NewProjectWizard::runWizard (Component* ownerWindow_)
project->setBundleIdentifierToDefault(); project->setBundleIdentifierToDefault();
if (! initialiseProject (*project)) if (! initialiseProject (*project))
return 0;
return nullptr;
if (project->save (false, true) != FileBasedDocument::savedOk) if (project->save (false, true) != FileBasedDocument::savedOk)
return 0;
return nullptr;
project->setChangedFlag (false); project->setChangedFlag (false);
} }
@@ -434,48 +410,160 @@ Project* NewProjectWizard::runWizard (Component* ownerWindow_)
"Errors in Creating Project!", "Errors in Creating Project!",
"The following files couldn't be written:\n\n" "The following files couldn't be written:\n\n"
+ failedFiles.joinIntoString ("\n", 0, 10)); + failedFiles.joinIntoString ("\n", 0, 10));
return 0;
return nullptr;
} }
return project.release(); return project.release();
} }
Project* NewProjectWizard::runNewProjectWizard (Component* ownerWindow)
//==============================================================================
class NewProjectWizard::WizardComp : public Component,
private ButtonListener,
private ComboBoxListener,
private TextEditorListener
{ {
ScopedPointer <NewProjectWizard> wizard;
public:
WizardComp()
: projectName ("Project name"),
nameLabel (String::empty, "Project Name:"),
typeLabel (String::empty, "Project Type:"),
fileBrowser (FileBrowserComponent::saveMode | FileBrowserComponent::canSelectDirectories,
getLastWizardFolder(), nullptr, nullptr),
fileOutline (String::empty, "Project Folder:"),
createButton ("Create..."),
cancelButton ("Cancel")
{
setOpaque (true);
setSize (600, 500);
projectName.setComponentID ("projectName");
projectName.setText ("NewProject");
projectName.setBounds ("100, 14, parent.width / 2 - 10, top + 22");
addAndMakeVisible (&projectName);
nameLabel.attachToComponent (&projectName, true);
projectName.addListener (this);
projectType.setComponentID ("projectType");
projectType.addItemList (getWizards(), 1);
projectType.setSelectedId (1, true);
projectType.setBounds ("100, projectName.bottom + 4, projectName.right, top + 22");
addAndMakeVisible (&projectType);
typeLabel.attachToComponent (&projectType, true);
projectType.addListener (this);
fileOutline.setComponentID ("fileOutline");
fileOutline.setColour (GroupComponent::outlineColourId, Colours::black.withAlpha (0.2f));
fileOutline.setTextLabelPosition (Justification::centred);
addAndMakeVisible (&fileOutline);
fileOutline.setBounds ("10, projectType.bottom + 20, projectType.right, parent.height - 10");
fileBrowser.setComponentID ("fileBrowser");
fileBrowser.setBounds ("fileOutline.left + 10, fileOutline.top + 20, fileOutline.right - 10, fileOutline.bottom - 12");
fileBrowser.setFilenameBoxLabel ("Folder:");
addAndMakeVisible (&fileBrowser);
createButton.setComponentID ("createButton");
createButton.setBounds ("right - 140, bottom - 24, parent.width - 10, parent.height - 10");
addAndMakeVisible (&createButton);
createButton.addListener (this);
cancelButton.setComponentID ("cancelButton");
cancelButton.setBounds ("right - 140, createButton.top, createButton.left - 10, createButton.bottom");
addAndMakeVisible (&cancelButton);
cancelButton.addListener (this);
updateCustomItems();
updateCreateButton();
}
void paint (Graphics& g)
{ {
AlertWindow aw ("New Juce Project",
"Select the type of project to create, and the location of your Juce folder",
AlertWindow::NoIcon,
ownerWindow);
g.fillAll (Colour::greyLevel (0.93f));
}
aw.addComboBox ("type", getWizards(), "Project Type");
void buttonClicked (Button* b)
{
if (b == &createButton)
{
createProject();
}
else
{
MainWindow* mw = dynamic_cast<MainWindow*> (getTopLevelComponent());
jassert (mw != nullptr);
FilenameComponent juceFolderSelector ("Juce Library Location", ModuleList::getLocalModulesFolder (nullptr),
true, true, false, "*", String::empty, "(Please select the folder containing Juce!)");
juceFolderSelector.setSize (350, 22);
JucerApplication::getApp()->closeWindow (mw);
}
}
aw.addCustomComponent (&juceFolderSelector);
void createProject()
{
MainWindow* mw = Component::findParentComponentOfClass<MainWindow>();
jassert (mw != nullptr);
aw.addButton ("Next", 1, KeyPress (KeyPress::returnKey));
aw.addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey));
ScopedPointer <NewProjectWizard> wizard (createWizard());
for (;;)
if (wizard != nullptr)
{ {
if (aw.runModalLoop() == 0)
return 0;
Result result (wizard->processResultsFromSetupItems (*this));
if (FileHelpers::isJuceFolder (juceFolderSelector.getCurrentFile()))
if (result.failed())
{ {
wizard = createWizard (aw.getComboBoxComponent ("type")->getSelectedItemIndex());
break;
AlertWindow::showMessageBox (AlertWindow::WarningIcon, "Create Project", result.getErrorMessage());
return;
} }
aw.setColour (AlertWindow::textColourId, Colours::red);
aw.setMessage ("Please select a valid Juce folder for the project to use!");
ScopedPointer<Project> project (wizard->runWizard (mw, projectName.getText(),
fileBrowser.getSelectedFile (0)));
if (project != nullptr)
mw->setProject (project.release());
} }
} }
return wizard != nullptr ? wizard->runWizard (ownerWindow) : 0;
void updateCustomItems()
{
customItems.clear();
ScopedPointer <NewProjectWizard> wizard (createWizard());
if (wizard != nullptr)
wizard->addSetupItems (*this, customItems);
}
void comboBoxChanged (ComboBox*)
{
updateCustomItems();
}
void textEditorTextChanged (TextEditor&)
{
updateCreateButton();
fileBrowser.setFileName (File::createLegalFileName (projectName.getText()));
}
private:
ComboBox projectType;
TextEditor projectName;
Label nameLabel, typeLabel;
FileBrowserComponent fileBrowser;
GroupComponent fileOutline;
TextButton createButton, cancelButton;
OwnedArray<Component> customItems;
NewProjectWizard* createWizard()
{
return NewProjectWizard::createWizard (projectType.getSelectedItemIndex());
}
void updateCreateButton()
{
createButton.setEnabled (projectName.getText().trim().isNotEmpty());
}
};
Component* NewProjectWizard::createComponent()
{
return new WizardComp();
} }

+ 10
- 4
extras/Introjucer/Source/Project/jucer_NewProjectWizard.h View File

@@ -41,14 +41,14 @@ public:
static int getNumWizards(); static int getNumWizards();
static NewProjectWizard* createWizard (int index); static NewProjectWizard* createWizard (int index);
static Project* runNewProjectWizard (Component* ownerWindow);
static Component* createComponent();
//============================================================================== //==============================================================================
virtual String getName() = 0; virtual String getName() = 0;
virtual String getDescription() = 0; virtual String getDescription() = 0;
virtual void addItemsToAlertWindow (AlertWindow& aw) = 0;
virtual String processResultsFromAlertWindow (AlertWindow& aw) = 0;
virtual void addSetupItems (Component& setupComp, OwnedArray<Component>& itemsCreated) = 0;
virtual Result processResultsFromSetupItems (Component& setupComp) = 0;
virtual bool initialiseProject (Project& project) = 0; virtual bool initialiseProject (Project& project) = 0;
protected: protected:
@@ -59,9 +59,15 @@ protected:
//============================================================================== //==============================================================================
NewProjectWizard(); NewProjectWizard();
Project* runWizard (Component* ownerWindow);
Project* runWizard (Component* ownerWindow,
const String& projectName,
const File& targetFolder);
class WizardComp;
friend class WizardComp;
File getSourceFilesFolder() const { return projectFile.getSiblingFile ("Source"); } File getSourceFilesFolder() const { return projectFile.getSiblingFile ("Source"); }
static File& getLastWizardFolder();
}; };


+ 25
- 19
extras/Introjucer/Source/Project/jucer_Project.cpp View File

@@ -128,25 +128,28 @@ void Project::setMissingDefaultValues()
setBundleIdentifierToDefault(); setBundleIdentifierToDefault();
if (! projectRoot.getChildWithName (Tags::modulesGroup).isValid()) if (! projectRoot.getChildWithName (Tags::modulesGroup).isValid())
{
addModule ("juce_core");
addDefaultModules (false);
}
if (! isConfigFlagEnabled ("JUCE_ONLY_BUILD_CORE_LIBRARY"))
{
addModule ("juce_events");
addModule ("juce_graphics");
addModule ("juce_data_structures");
addModule ("juce_gui_basics");
addModule ("juce_gui_extra");
addModule ("juce_gui_audio");
addModule ("juce_cryptography");
addModule ("juce_video");
addModule ("juce_opengl");
addModule ("juce_audio_basics");
addModule ("juce_audio_devices");
addModule ("juce_audio_formats");
addModule ("juce_audio_processors");
}
void Project::addDefaultModules (bool shouldCopyFilesLocally)
{
addModule ("juce_core", shouldCopyFilesLocally);
if (! isConfigFlagEnabled ("JUCE_ONLY_BUILD_CORE_LIBRARY"))
{
addModule ("juce_events", shouldCopyFilesLocally);
addModule ("juce_graphics", shouldCopyFilesLocally);
addModule ("juce_data_structures", shouldCopyFilesLocally);
addModule ("juce_gui_basics", shouldCopyFilesLocally);
addModule ("juce_gui_extra", shouldCopyFilesLocally);
addModule ("juce_gui_audio", shouldCopyFilesLocally);
addModule ("juce_cryptography", shouldCopyFilesLocally);
addModule ("juce_video", shouldCopyFilesLocally);
addModule ("juce_opengl", shouldCopyFilesLocally);
addModule ("juce_audio_basics", shouldCopyFilesLocally);
addModule ("juce_audio_devices", shouldCopyFilesLocally);
addModule ("juce_audio_formats", shouldCopyFilesLocally);
addModule ("juce_audio_processors", shouldCopyFilesLocally);
} }
} }
@@ -835,7 +838,7 @@ Value Project::shouldCopyModuleFilesLocally (const String& moduleID)
.getPropertyAsValue (Ids::useLocalCopy, getUndoManagerFor (getModulesNode())); .getPropertyAsValue (Ids::useLocalCopy, getUndoManagerFor (getModulesNode()));
} }
void Project::addModule (const String& moduleID)
void Project::addModule (const String& moduleID, bool shouldCopyFilesLocally)
{ {
if (! isModuleEnabled (moduleID)) if (! isModuleEnabled (moduleID))
{ {
@@ -847,6 +850,9 @@ void Project::addModule (const String& moduleID)
shouldShowAllModuleFilesInProject (moduleID) = true; shouldShowAllModuleFilesInProject (moduleID) = true;
} }
if (shouldCopyFilesLocally)
shouldCopyModuleFilesLocally (moduleID) = true;
} }
void Project::removeModule (const String& moduleID) void Project::removeModule (const String& moduleID)


+ 2
- 1
extras/Introjucer/Source/Project/jucer_Project.h View File

@@ -273,10 +273,11 @@ public:
Value shouldShowAllModuleFilesInProject (const String& moduleID); Value shouldShowAllModuleFilesInProject (const String& moduleID);
Value shouldCopyModuleFilesLocally (const String& moduleID); Value shouldCopyModuleFilesLocally (const String& moduleID);
void addModule (const String& moduleID);
void addModule (const String& moduleID, bool shouldCopyFilesLocally);
void removeModule (const String& moduleID); void removeModule (const String& moduleID);
int getNumModules() const; int getNumModules() const;
String getModuleID (int index) const; String getModuleID (int index) const;
void addDefaultModules (bool shouldCopyFilesLocally);
void createRequiredModules (const ModuleList& availableModules, OwnedArray<LibraryModule>& modules) const; void createRequiredModules (const ModuleList& availableModules, OwnedArray<LibraryModule>& modules) const;


+ 117
- 70
extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.cpp View File

@@ -107,19 +107,6 @@ private:
int exporterIndex; int exporterIndex;
}; };
//==============================================================================
static StringArray getExtraDependenciesNeeded (Project& project, ModuleList& moduleList, const ModuleList::Module& m)
{
StringArray dependencies, extraDepsNeeded;
moduleList.getDependencies (m.uid, dependencies);
for (int i = 0; i < dependencies.size(); ++i)
if ((! project.isModuleEnabled (dependencies[i])) && dependencies[i] != m.uid)
extraDepsNeeded.add (dependencies[i]);
return extraDepsNeeded;
}
//============================================================================== //==============================================================================
class ModuleSettingsPanel : public PanelBase class ModuleSettingsPanel : public PanelBase
{ {
@@ -141,7 +128,7 @@ public:
if (project.isModuleEnabled (moduleID)) if (project.isModuleEnabled (moduleID))
{ {
const ModuleList::Module* m = moduleList.findModuleInfo (moduleID); const ModuleList::Module* m = moduleList.findModuleInfo (moduleID);
if (m != nullptr && getExtraDependenciesNeeded (project, moduleList, *m).size() > 0)
if (m != nullptr && moduleList.getExtraDependenciesNeeded (project, *m).size() > 0)
props.add (new MissingDependenciesComponent (project, moduleList, moduleID)); props.add (new MissingDependenciesComponent (project, moduleList, moduleID));
} }
@@ -239,7 +226,7 @@ private:
const ModuleList::Module* module = moduleList.findModuleInfo (moduleID); const ModuleList::Module* module = moduleList.findModuleInfo (moduleID);
if (module != nullptr) if (module != nullptr)
missingDependencies = getExtraDependenciesNeeded (project, moduleList, *module);
missingDependencies = moduleList.getExtraDependenciesNeeded (project, *module);
addAndMakeVisible (&fixButton); addAndMakeVisible (&fixButton);
fixButton.setColour (TextButton::buttonColourId, Colours::red); fixButton.setColour (TextButton::buttonColourId, Colours::red);
@@ -277,42 +264,26 @@ private:
}; };
}; };
//============================================================================== //==============================================================================
class ModulesPanel : public Component,
public ListBoxModel,
public FilenameComponentListener,
public ButtonListener
class ModuleSelectionListBox : public ListBox,
public ListBoxModel
{ {
public: public:
ModulesPanel (Project& project_)
: project (project_),
moduleList (ModuleList::getLocalModulesFolder (&project)),
modulesLocation ("modules", moduleList.getModulesFolder(),
true, true, false, "*", String::empty,
"Select a folder containing your JUCE modules..."),
modulesLabel (String::empty, "Module source folder:"),
updateModulesButton ("Check for module updates...")
ModuleSelectionListBox (ModuleList& list_)
: list (list_), handler (nullptr)
{ {
addAndMakeVisible (&modulesLocation);
modulesLocation.setBounds ("150, 3, parent.width - 180, 28");
modulesLocation.addListener (this);
modulesLabel.attachToComponent (&modulesLocation, true);
addAndMakeVisible (&updateModulesButton);
updateModulesButton.setBounds ("parent.width - 175, 3, parent.width - 4, 28");
updateModulesButton.addListener (this);
setColour (ListBox::backgroundColourId, Colours::white.withAlpha (0.4f));
}
modulesList.setModel (this);
modulesList.setColour (ListBox::backgroundColourId, Colours::white.withAlpha (0.4f));
addAndMakeVisible (&modulesList);
modulesList.setBounds ("4, 31, parent.width / 2 - 4, parent.height - 3");
void refresh()
{
updateContent();
repaint();
} }
int getNumRows() int getNumRows()
{ {
return moduleList.modules.size();
return list.modules.size();
} }
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
@@ -320,16 +291,16 @@ public:
if (rowIsSelected) if (rowIsSelected)
g.fillAll (findColour (TextEditor::highlightColourId)); g.fillAll (findColour (TextEditor::highlightColourId));
const ModuleList::Module* const m = moduleList.modules [rowNumber];
const ModuleList::Module* const m = list.modules [rowNumber];
if (m != nullptr) if (m != nullptr)
{ {
const float tickSize = height * 0.7f; const float tickSize = height * 0.7f;
getLookAndFeel().drawTickBox (g, *this, (height - tickSize) / 2, (height - tickSize) / 2, tickSize, tickSize, getLookAndFeel().drawTickBox (g, *this, (height - tickSize) / 2, (height - tickSize) / 2, tickSize, tickSize,
project.isModuleEnabled (m->uid), true, false, false);
handler->isEnabled (m), true, false, false);
if (project.isModuleEnabled (m->uid) && getExtraDependenciesNeeded (project, moduleList, *m).size() > 0)
if (handler->isEnabled (m) && handler->areDependenciesMissing (m))
g.setColour (Colours::red); g.setColour (Colours::red);
else else
g.setColour (Colours::black); g.setColour (Colours::black);
@@ -342,19 +313,91 @@ public:
} }
} }
void listBoxItemClicked (int row, const MouseEvent& e)
{
if (e.x < getRowHeight())
flipRow (row);
}
void listBoxItemDoubleClicked (int row, const MouseEvent& e)
{
flipRow (row);
}
void returnKeyPressed (int row)
{
flipRow (row);
}
void selectedRowsChanged (int lastRowSelected)
{
handler->selectionChanged (list.modules [lastRowSelected]);
}
void flipRow (int row) void flipRow (int row)
{ {
const ModuleList::Module* const m = moduleList.modules [row];
const ModuleList::Module* const m = list.modules [row];
if (m != nullptr) if (m != nullptr)
{
if (project.isModuleEnabled (m->uid))
project.removeModule (m->uid);
else
project.addModule (m->uid);
}
handler->setEnabled (m, ! handler->isEnabled (m));
}
refresh();
//==============================================================================
class Handler
{
public:
Handler() {}
virtual ~Handler() {};
virtual bool isEnabled (const ModuleList::Module* m) const = 0;
virtual void setEnabled (const ModuleList::Module* m, bool enable) = 0;
virtual bool areDependenciesMissing (const ModuleList::Module* m) = 0;
virtual void selectionChanged (const ModuleList::Module* selectedModule) = 0;
};
void setHandler (Handler* h)
{
handler = h;
setModel (this);
}
private:
ModuleList& list;
Handler* handler;
};
//==============================================================================
class ModulesPanel : public Component,
public ModuleSelectionListBox::Handler,
public FilenameComponentListener,
public ButtonListener
{
public:
ModulesPanel (Project& project_)
: project (project_),
modulesLocation ("modules", ModuleList::getLocalModulesFolder (&project),
true, true, false, "*", String::empty,
"Select a folder containing your JUCE modules..."),
modulesLabel (String::empty, "Module source folder:"),
updateModulesButton ("Check for module updates..."),
moduleListBox (moduleList)
{
moduleList.rescan (ModuleList::getLocalModulesFolder (&project));
addAndMakeVisible (&modulesLocation);
modulesLocation.setBounds ("150, 3, parent.width - 180, 28");
modulesLocation.addListener (this);
modulesLabel.attachToComponent (&modulesLocation, true);
addAndMakeVisible (&updateModulesButton);
updateModulesButton.setBounds ("parent.width - 175, 3, parent.width - 4, 28");
updateModulesButton.addListener (this);
moduleListBox.setHandler (this);
addAndMakeVisible (&moduleListBox);
moduleListBox.setBounds ("4, 31, parent.width / 2 - 4, parent.height - 3");
} }
void filenameComponentChanged (FilenameComponent*) void filenameComponentChanged (FilenameComponent*)
@@ -362,45 +405,47 @@ public:
moduleList.rescan (modulesLocation.getCurrentFile()); moduleList.rescan (modulesLocation.getCurrentFile());
modulesLocation.setCurrentFile (moduleList.getModulesFolder(), false, false); modulesLocation.setCurrentFile (moduleList.getModulesFolder(), false, false);
ModuleList::setLocalModulesFolder (moduleList.getModulesFolder()); ModuleList::setLocalModulesFolder (moduleList.getModulesFolder());
modulesList.updateContent();
moduleListBox.refresh();
} }
void buttonClicked (Button*) void buttonClicked (Button*)
{ {
JuceUpdater::show (moduleList, getTopLevelComponent());
JuceUpdater::show (moduleList, getTopLevelComponent(), "");
filenameComponentChanged (nullptr); filenameComponentChanged (nullptr);
} }
void listBoxItemClicked (int row, const MouseEvent& e)
bool isEnabled (const ModuleList::Module* m) const
{ {
if (e.x < modulesList.getRowHeight())
flipRow (row);
return project.isModuleEnabled (m->uid);
} }
void listBoxItemDoubleClicked (int row, const MouseEvent& e)
void setEnabled (const ModuleList::Module* m, bool enable)
{ {
flipRow (row);
if (enable)
project.addModule (m->uid, true);
else
project.removeModule (m->uid);
refresh();
} }
void returnKeyPressed (int row)
bool areDependenciesMissing (const ModuleList::Module* m)
{ {
flipRow (row);
return moduleList.getExtraDependenciesNeeded (project, *m).size() > 0;
} }
void selectedRowsChanged (int lastRowSelected)
void selectionChanged (const ModuleList::Module* selectedModule)
{ {
const ModuleList::Module* const m = moduleList.modules [lastRowSelected];
settings = nullptr; settings = nullptr;
if (m != nullptr)
addAndMakeVisible (settings = new ModuleSettingsPanel (project, moduleList, m->uid));
if (selectedModule != nullptr)
addAndMakeVisible (settings = new ModuleSettingsPanel (project, moduleList, selectedModule->uid));
} }
void refresh() void refresh()
{ {
modulesList.repaint();
moduleListBox.refresh();
if (settings != nullptr) if (settings != nullptr)
settings->refreshAll(); settings->refreshAll();
@@ -412,14 +457,16 @@ private:
FilenameComponent modulesLocation; FilenameComponent modulesLocation;
Label modulesLabel; Label modulesLabel;
TextButton updateModulesButton; TextButton updateModulesButton;
ListBox modulesList;
ModuleSelectionListBox moduleListBox;
ScopedPointer<ModuleSettingsPanel> settings; ScopedPointer<ModuleSettingsPanel> settings;
}; };
void ModuleSettingsPanel::MissingDependenciesComponent::buttonClicked (Button*) void ModuleSettingsPanel::MissingDependenciesComponent::buttonClicked (Button*)
{ {
bool isModuleCopiedLocally = project.shouldCopyModuleFilesLocally (moduleID).getValue();
for (int i = missingDependencies.size(); --i >= 0;) for (int i = missingDependencies.size(); --i >= 0;)
project.addModule (missingDependencies[i]);
project.addModule (missingDependencies[i], isModuleCopiedLocally);
ModulesPanel* mp = findParentComponentOfClass ((ModulesPanel*) 0); ModulesPanel* mp = findParentComponentOfClass ((ModulesPanel*) 0);
if (mp != nullptr) if (mp != nullptr)


+ 0
- 43
extras/Introjucer/Source/Utility/jucer_FileHelpers.cpp View File

@@ -145,47 +145,4 @@ namespace FileHelpers
return path1.substring (0, commonBitLength).removeCharacters ("/:").isNotEmpty(); return path1.substring (0, commonBitLength).removeCharacters ("/:").isNotEmpty();
} }
//==============================================================================
bool isJuceFolder (const File& folder)
{
return folder.getFileName().containsIgnoreCase ("juce")
&& isModulesFolder (folder.getChildFile ("modules"));
}
bool isModulesFolder (const File& folder)
{
return folder.getFileName().equalsIgnoreCase ("modules")
&& folder.isDirectory();
}
File lookInFolderForJuceFolder (const File& folder)
{
for (DirectoryIterator di (folder, false, "*juce*", File::findDirectories); di.next();)
{
if (isJuceFolder (di.getFile()))
return di.getFile();
}
return File::nonexistent;
}
File findParentJuceFolder (const File& file)
{
File f (file);
while (f.exists() && f.getParentDirectory() != f)
{
if (isJuceFolder (f))
return f;
File found = lookInFolderForJuceFolder (f);
if (found.exists())
return found;
f = f.getParentDirectory();
}
return File::nonexistent;
}
} }

+ 0
- 6
extras/Introjucer/Source/Utility/jucer_FileHelpers.h View File

@@ -43,12 +43,6 @@ namespace FileHelpers
String windowsStylePath (const String& path); String windowsStylePath (const String& path);
bool shouldPathsBeRelative (String path1, String path2); bool shouldPathsBeRelative (String path1, String path2);
//==============================================================================
bool isJuceFolder (const File& folder);
bool isModulesFolder (const File& folder);
File findParentJuceFolder (const File& file);
File lookInFolderForJuceFolder (const File& folder);
} }
//============================================================================== //==============================================================================


+ 3
- 11
extras/Introjucer/Source/Utility/jucer_MiscUtilities.cpp View File

@@ -27,18 +27,10 @@
//============================================================================== //==============================================================================
int64 hashCode64 (const String& s)
{
MD5 md5 (s.toUTF8());
const uint64* const m = reinterpret_cast <const uint64*> (md5.getChecksumDataArray());
return (int64) ByteOrder::swapIfBigEndian (m[0] ^ m[1]);
}
String createAlphaNumericUID() String createAlphaNumericUID()
{ {
String uid; String uid;
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random r; Random r;
uid << chars [r.nextInt (52)]; // make sure the first character is always a letter uid << chars [r.nextInt (52)]; // make sure the first character is always a letter
@@ -46,7 +38,7 @@ String createAlphaNumericUID()
for (int i = 5; --i >= 0;) for (int i = 5; --i >= 0;)
{ {
r.setSeedRandomly(); r.setSeedRandomly();
uid << chars [r.nextInt (numElementsInArray (chars))];
uid << chars [r.nextInt (62)];
} }
return uid; return uid;
@@ -65,7 +57,7 @@ String createGUID (const String& seed)
+ "-" + hex.substring (8, 12) + "-" + hex.substring (8, 12)
+ "-" + hex.substring (12, 16) + "-" + hex.substring (12, 16)
+ "-" + hex.substring (16, 20) + "-" + hex.substring (16, 20)
+ "-" + hex.substring (20, 32)
+ "-" + hex.substring (20, 32)
+ "}"; + "}";
} }


+ 0
- 2
extras/Introjucer/Source/Utility/jucer_MiscUtilities.h View File

@@ -24,8 +24,6 @@
*/ */
//============================================================================== //==============================================================================
// String::hashCode64 actually hit some dupes, so this is a more powerful version.
int64 hashCode64 (const String& s);
String hexString8Digits (int value); String hexString8Digits (int value);
String createAlphaNumericUID(); String createAlphaNumericUID();


+ 3
- 3
extras/Introjucer/Source/Utility/jucer_StoredSettings.cpp View File

@@ -73,7 +73,7 @@ void StoredSettings::flush()
// These settings are used in defining the properties file's location. // These settings are used in defining the properties file's location.
PropertiesFile::Options options; PropertiesFile::Options options;
options.applicationName = "Introjucer"; options.applicationName = "Introjucer";
options.folderName = "Introjucer";
options.folderName = "Introjucerxx";
options.filenameSuffix = "settings"; options.filenameSuffix = "settings";
options.osxLibrarySubFolder = "Application Support"; options.osxLibrarySubFolder = "Application Support";
@@ -81,7 +81,7 @@ void StoredSettings::flush()
// Because older versions of the introjucer saved their settings under a different // Because older versions of the introjucer saved their settings under a different
// name, this code is an example of how to migrate your old settings files... // name, this code is an example of how to migrate your old settings files...
if (! props->getFile().exists())
/* if (! props->getFile().exists())
{ {
PropertiesFile::Options oldOptions; PropertiesFile::Options oldOptions;
oldOptions.applicationName = "Jucer2"; oldOptions.applicationName = "Jucer2";
@@ -93,7 +93,7 @@ void StoredSettings::flush()
if (oldProps.getFile().exists()) if (oldProps.getFile().exists())
props->addAllPropertiesFrom (oldProps); props->addAllPropertiesFrom (oldProps);
} }
}
*/ }
// recent files... // recent files...
recentFiles.restoreFromString (props->getValue ("recentFiles")); recentFiles.restoreFromString (props->getValue ("recentFiles"));


Loading…
Cancel
Save