| @@ -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); | ||||
| @@ -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; | ||||
| @@ -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) | ||||
| @@ -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 (¤tVersionLabel); | addAndMakeVisible (¤tVersionLabel); | ||||
| 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); | ||||
| } | } | ||||
| } | } | ||||
| @@ -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; | ||||
| @@ -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() | ||||
| @@ -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); | ||||
| }; | }; | ||||
| @@ -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); | ||||
| @@ -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); | ||||
| } | } | ||||
| @@ -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()); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -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; | ||||
| @@ -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(); | |||||
| } | } | ||||
| @@ -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(); | |||||
| }; | }; | ||||
| @@ -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) | ||||
| @@ -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; | ||||
| @@ -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) | ||||
| @@ -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; | |||||
| } | |||||
| } | } | ||||
| @@ -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); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -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) | |||||
| + "}"; | + "}"; | ||||
| } | } | ||||
| @@ -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(); | ||||
| @@ -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")); | ||||