From 5bdfa1bf52038ad0dd00c0e00d1607352f5d5d5f Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 18 Nov 2014 11:12:31 +0200 Subject: [PATCH] Whitespace cleanups. --- .../Source/Application/jucer_Application.h | 1172 +++++++------- .../Project Saving/jucer_ProjectExporter.cpp | 1442 ++++++++--------- 2 files changed, 1307 insertions(+), 1307 deletions(-) diff --git a/extras/Introjucer/Source/Application/jucer_Application.h b/extras/Introjucer/Source/Application/jucer_Application.h index b319eb5cb5..6e4c09d394 100644 --- a/extras/Introjucer/Source/Application/jucer_Application.h +++ b/extras/Introjucer/Source/Application/jucer_Application.h @@ -1,586 +1,586 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2013 - Raw Material Software Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -#ifndef __JUCER_APPLICATION_JUCEHEADER__ -#define __JUCER_APPLICATION_JUCEHEADER__ - -#include "../jucer_Headers.h" -#include "jucer_MainWindow.h" -#include "jucer_CommandLine.h" -#include "../project/jucer_Module.h" -#include "jucer_AutoUpdater.h" -#include "../Code Editor/jucer_SourceCodeEditor.h" - -void createGUIEditorMenu (PopupMenu&); -void handleGUIEditorMenuCommand (int); -void registerGUIEditorCommands(); - -//============================================================================== -class IntrojucerApp : public JUCEApplication -{ -public: - //============================================================================== - IntrojucerApp() : isRunningCommandLine (false) {} - - //============================================================================== - void initialise (const String& commandLine) override - { - LookAndFeel::setDefaultLookAndFeel (&lookAndFeel); - settings = new StoredSettings(); - - if (commandLine.isNotEmpty()) - { - const int appReturnCode = performCommandLine (commandLine); - - if (appReturnCode != commandLineNotPerformed) - { - isRunningCommandLine = true; - setApplicationReturnValue (appReturnCode); - quit(); - return; - } - } - - if (sendCommandLineToPreexistingInstance()) - { - DBG ("Another instance is running - quitting..."); - quit(); - return; - } - - initialiseLogger ("log_"); - - icons = new Icons(); - - initCommandManager(); - - menuModel = new MainMenuModel(); - - doExtraInitialisation(); - - settings->appearance.refreshPresetSchemeList(); - - ImageCache::setCacheTimeout (30 * 1000); - - if (commandLine.trim().isNotEmpty() && ! commandLine.trim().startsWithChar ('-')) - anotherInstanceStarted (commandLine); - else - mainWindowList.reopenLastProjects(); - - mainWindowList.createWindowIfNoneAreOpen(); - - #if JUCE_MAC - MenuBarModel::setMacMainMenu (menuModel, nullptr, "Open Recent"); - #endif - - versionChecker = new LatestVersionChecker(); - } - - void shutdown() override - { - versionChecker = nullptr; - appearanceEditorWindow = nullptr; - utf8Window = nullptr; - svgPathWindow = nullptr; - - mainWindowList.forceCloseAllWindows(); - openDocumentManager.clear(); - commandManager = nullptr; - settings = nullptr; - - #if JUCE_MAC - MenuBarModel::setMacMainMenu (nullptr); - #endif - menuModel = nullptr; - - LookAndFeel::setDefaultLookAndFeel (nullptr); - - if (! isRunningCommandLine) - Logger::writeToLog ("Shutdown"); - - deleteLogger(); - } - - //============================================================================== - void systemRequestedQuit() override - { - if (ModalComponentManager::getInstance()->cancelAllModalComponents()) - { - new AsyncQuitRetrier(); - } - else - { - if (closeAllMainWindows()) - quit(); - } - } - - //============================================================================== - const String getApplicationName() override { return "Introjucer"; } - const String getApplicationVersion() override { return ProjectInfo::versionString; } - - bool moreThanOneInstanceAllowed() override - { - return true; // this is handled manually in initialise() - } - - void anotherInstanceStarted (const String& commandLine) override - { - openFile (File (commandLine.unquoted())); - } - - static IntrojucerApp& getApp() - { - IntrojucerApp* const app = dynamic_cast (JUCEApplication::getInstance()); - jassert (app != nullptr); - return *app; - } - - static ApplicationCommandManager& getCommandManager() - { - ApplicationCommandManager* cm = IntrojucerApp::getApp().commandManager; - jassert (cm != nullptr); - return *cm; - } - - //============================================================================== - class MainMenuModel : public MenuBarModel - { - public: - MainMenuModel() - { - setApplicationCommandManagerToWatch (&getCommandManager()); - } - - StringArray getMenuBarNames() override - { - return getApp().getMenuNames(); - } - - PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName) override - { - PopupMenu menu; - getApp().createMenu (menu, menuName); - return menu; - } - - void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) override - { - getApp().handleMainMenuCommand (menuItemID); - } - }; - - enum - { - recentProjectsBaseID = 100, - activeDocumentsBaseID = 300, - colourSchemeBaseID = 1000 - }; - - virtual StringArray getMenuNames() - { - const char* const names[] = { "File", "Edit", "View", "Window", "GUI Editor", "Tools", nullptr }; - return StringArray (names); - } - - virtual void createMenu (PopupMenu& menu, const String& menuName) - { - if (menuName == "File") createFileMenu (menu); - else if (menuName == "Edit") createEditMenu (menu); - else if (menuName == "View") createViewMenu (menu); - else if (menuName == "Window") createWindowMenu (menu); - else if (menuName == "Tools") createToolsMenu (menu); - else if (menuName == "GUI Editor") createGUIEditorMenu (menu); - else jassertfalse; // names have changed? - } - - virtual void createFileMenu (PopupMenu& menu) - { - menu.addCommandItem (commandManager, CommandIDs::newProject); - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::open); - - PopupMenu recentFiles; - settings->recentFiles.createPopupMenuItems (recentFiles, recentProjectsBaseID, true, true); - menu.addSubMenu ("Open Recent", recentFiles); - - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::closeDocument); - menu.addCommandItem (commandManager, CommandIDs::saveDocument); - menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs); - menu.addCommandItem (commandManager, CommandIDs::saveAll); - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::closeProject); - menu.addCommandItem (commandManager, CommandIDs::saveProject); - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::openInIDE); - menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE); - - #if ! JUCE_MAC - menu.addSeparator(); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit); - #endif - } - - virtual void createEditMenu (PopupMenu& menu) - { - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::undo); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::redo); - menu.addSeparator(); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll); - menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll); - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::showFindPanel); - menu.addCommandItem (commandManager, CommandIDs::findSelection); - menu.addCommandItem (commandManager, CommandIDs::findNext); - menu.addCommandItem (commandManager, CommandIDs::findPrevious); - } - - virtual void createViewMenu (PopupMenu& menu) - { - menu.addCommandItem (commandManager, CommandIDs::showFilePanel); - menu.addCommandItem (commandManager, CommandIDs::showConfigPanel); - menu.addCommandItem (commandManager, CommandIDs::showProjectSettings); - menu.addCommandItem (commandManager, CommandIDs::showProjectModules); - menu.addSeparator(); - createColourSchemeItems (menu); - } - - void createColourSchemeItems (PopupMenu& menu) - { - menu.addCommandItem (commandManager, CommandIDs::showAppearanceSettings); - - const StringArray presetSchemes (settings->appearance.getPresetSchemes()); - - if (presetSchemes.size() > 0) - { - PopupMenu schemes; - - for (int i = 0; i < presetSchemes.size(); ++i) - schemes.addItem (colourSchemeBaseID + i, presetSchemes[i]); - - menu.addSubMenu ("Colour Scheme", schemes); - } - } - - virtual void createWindowMenu (PopupMenu& menu) - { - menu.addCommandItem (commandManager, CommandIDs::closeWindow); - menu.addSeparator(); - - menu.addCommandItem (commandManager, CommandIDs::goToPreviousDoc); - menu.addCommandItem (commandManager, CommandIDs::goToNextDoc); - menu.addCommandItem (commandManager, CommandIDs::goToCounterpart); - menu.addSeparator(); - - const int numDocs = jmin (50, openDocumentManager.getNumOpenDocuments()); - - for (int i = 0; i < numDocs; ++i) - { - OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument(i); - menu.addItem (activeDocumentsBaseID + i, doc->getName()); - } - - menu.addSeparator(); - menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments); - } - - virtual void createToolsMenu (PopupMenu& menu) - { - menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool); - menu.addCommandItem (commandManager, CommandIDs::showSVGPathTool); - menu.addCommandItem (commandManager, CommandIDs::showTranslationTool); - } - - virtual void handleMainMenuCommand (int menuItemID) - { - if (menuItemID >= recentProjectsBaseID && menuItemID < recentProjectsBaseID + 100) - { - // open a file from the "recent files" menu - openFile (settings->recentFiles.getFile (menuItemID - recentProjectsBaseID)); - } - else if (menuItemID >= activeDocumentsBaseID && menuItemID < activeDocumentsBaseID + 200) - { - if (OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument (menuItemID - activeDocumentsBaseID)) - mainWindowList.openDocument (doc, true); - else - jassertfalse; - } - else if (menuItemID >= colourSchemeBaseID && menuItemID < colourSchemeBaseID + 200) - { - settings->appearance.selectPresetScheme (menuItemID - colourSchemeBaseID); - } - else - { - handleGUIEditorMenuCommand (menuItemID); - } - } - - //============================================================================== - void getAllCommands (Array & commands) override - { - JUCEApplication::getAllCommands (commands); - - const CommandID ids[] = { CommandIDs::newProject, - CommandIDs::open, - CommandIDs::closeAllDocuments, - CommandIDs::saveAll, - CommandIDs::showAppearanceSettings, - CommandIDs::showUTF8Tool, - CommandIDs::showSVGPathTool }; - - commands.addArray (ids, numElementsInArray (ids)); - } - - void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override - { - switch (commandID) - { - case CommandIDs::newProject: - result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0)); - break; - - case CommandIDs::open: - result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0)); - break; - - case CommandIDs::showAppearanceSettings: - result.setInfo ("Fonts and Colours...", "Shows the appearance settings window.", CommandCategories::general, 0); - break; - - case CommandIDs::closeAllDocuments: - result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0); - result.setActive (openDocumentManager.getNumOpenDocuments() > 0); - break; - - case CommandIDs::saveAll: - result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::altModifier, 0)); - break; - - case CommandIDs::showUTF8Tool: - result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0); - break; - - case CommandIDs::showSVGPathTool: - result.setInfo ("SVG Path Helper", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0); - break; - - default: - JUCEApplication::getCommandInfo (commandID, result); - break; - } - } - - bool perform (const InvocationInfo& info) override - { - switch (info.commandID) - { - case CommandIDs::newProject: createNewProject(); break; - case CommandIDs::open: askUserToOpenFile(); break; - case CommandIDs::saveAll: openDocumentManager.saveAll(); break; - case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; - case CommandIDs::showUTF8Tool: showUTF8ToolWindow (utf8Window); break; - case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow (svgPathWindow); break; - - case CommandIDs::showAppearanceSettings: AppearanceSettings::showEditorWindow (appearanceEditorWindow); break; - default: return JUCEApplication::perform (info); - } - - return true; - } - - //============================================================================== - void createNewProject() - { - MainWindow* mw = mainWindowList.getOrCreateEmptyWindow(); - mw->showNewProjectWizard(); - mainWindowList.avoidSuperimposedWindows (mw); - } - - virtual void updateNewlyOpenedProject (Project&) {} - - void askUserToOpenFile() - { - FileChooser fc ("Open File"); - - if (fc.browseForFileToOpen()) - openFile (fc.getResult()); - } - - bool openFile (const File& file) - { - return mainWindowList.openFile (file); - } - - bool closeAllDocuments (bool askUserToSave) - { - return openDocumentManager.closeAll (askUserToSave); - } - - virtual bool closeAllMainWindows() - { - return mainWindowList.askAllWindowsToClose(); - } - - //============================================================================== - void initialiseLogger (const char* filePrefix) - { - if (logger == nullptr) - { - logger = FileLogger::createDateStampedLogger (getLogFolderName(), filePrefix, ".txt", - getApplicationName() + " " + getApplicationVersion() - + " --- Build date: " __DATE__); - Logger::setCurrentLogger (logger); - } - } - - struct FileWithTime - { - FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {} - FileWithTime() {} - - bool operator< (const FileWithTime& other) const { return time < other.time; } - bool operator== (const FileWithTime& other) const { return time == other.time; } - - File file; - Time time; - }; - - void deleteLogger() - { - const int maxNumLogFilesToKeep = 50; - - Logger::setCurrentLogger (nullptr); - - if (logger != nullptr) - { - Array logFiles; - logger->getLogFile().getParentDirectory().findChildFiles (logFiles, File::findFiles, false); - - if (logFiles.size() > maxNumLogFilesToKeep) - { - Array files; - - for (int i = 0; i < logFiles.size(); ++i) - files.addUsingDefaultSort (logFiles.getReference(i)); - - for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i) - files.getReference(i).file.deleteFile(); - } - } - - logger = nullptr; - } - - virtual void doExtraInitialisation() {} - virtual void addExtraConfigItems (Project&, TreeViewItem&) {} - - #if JUCE_LINUX - virtual String getLogFolderName() const { return "~/.config/Introjucer/Logs"; } - #else - virtual String getLogFolderName() const { return "com.juce.introjucer"; } - #endif - - virtual PropertiesFile::Options getPropertyFileOptionsFor (const String& filename) - { - PropertiesFile::Options options; - options.applicationName = filename; - options.filenameSuffix = "settings"; - options.osxLibrarySubFolder = "Application Support"; - #if JUCE_LINUX - options.folderName = "~/.config/Introjucer"; - #else - options.folderName = "Introjucer"; - #endif - - return options; - } - - virtual Component* createProjectContentComponent() const - { - return new ProjectContentComponent(); - } - - //============================================================================== - IntrojucerLookAndFeel lookAndFeel; - - ScopedPointer settings; - ScopedPointer icons; - - ScopedPointer menuModel; - - MainWindowList mainWindowList; - OpenDocumentManager openDocumentManager; - ScopedPointer commandManager; - - ScopedPointer appearanceEditorWindow, utf8Window, svgPathWindow; - - ScopedPointer logger; - - bool isRunningCommandLine; - -private: - ScopedPointer versionChecker; - - class AsyncQuitRetrier : private Timer - { - public: - AsyncQuitRetrier() { startTimer (500); } - - void timerCallback() override - { - stopTimer(); - delete this; - - if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance()) - app->systemRequestedQuit(); - } - - JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier) - }; - - void initCommandManager() - { - commandManager = new ApplicationCommandManager(); - commandManager->registerAllCommandsForTarget (this); - - { - CodeDocument doc; - CppCodeEditorComponent ed (File::nonexistent, doc); - commandManager->registerAllCommandsForTarget (&ed); - } - - registerGUIEditorCommands(); - } -}; - - -#endif // __JUCER_APPLICATION_JUCEHEADER__ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2013 - Raw Material Software Ltd. + + Permission is granted to use this software under the terms of either: + a) the GPL v2 (or any later version) + b) the Affero GPL v3 + + Details of these licenses can be found at: www.gnu.org/licenses + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.juce.com for more information. + + ============================================================================== +*/ + +#ifndef __JUCER_APPLICATION_JUCEHEADER__ +#define __JUCER_APPLICATION_JUCEHEADER__ + +#include "../jucer_Headers.h" +#include "jucer_MainWindow.h" +#include "jucer_CommandLine.h" +#include "../project/jucer_Module.h" +#include "jucer_AutoUpdater.h" +#include "../Code Editor/jucer_SourceCodeEditor.h" + +void createGUIEditorMenu (PopupMenu&); +void handleGUIEditorMenuCommand (int); +void registerGUIEditorCommands(); + +//============================================================================== +class IntrojucerApp : public JUCEApplication +{ +public: + //============================================================================== + IntrojucerApp() : isRunningCommandLine (false) {} + + //============================================================================== + void initialise (const String& commandLine) override + { + LookAndFeel::setDefaultLookAndFeel (&lookAndFeel); + settings = new StoredSettings(); + + if (commandLine.isNotEmpty()) + { + const int appReturnCode = performCommandLine (commandLine); + + if (appReturnCode != commandLineNotPerformed) + { + isRunningCommandLine = true; + setApplicationReturnValue (appReturnCode); + quit(); + return; + } + } + + if (sendCommandLineToPreexistingInstance()) + { + DBG ("Another instance is running - quitting..."); + quit(); + return; + } + + initialiseLogger ("log_"); + + icons = new Icons(); + + initCommandManager(); + + menuModel = new MainMenuModel(); + + doExtraInitialisation(); + + settings->appearance.refreshPresetSchemeList(); + + ImageCache::setCacheTimeout (30 * 1000); + + if (commandLine.trim().isNotEmpty() && ! commandLine.trim().startsWithChar ('-')) + anotherInstanceStarted (commandLine); + else + mainWindowList.reopenLastProjects(); + + mainWindowList.createWindowIfNoneAreOpen(); + + #if JUCE_MAC + MenuBarModel::setMacMainMenu (menuModel, nullptr, "Open Recent"); + #endif + + versionChecker = new LatestVersionChecker(); + } + + void shutdown() override + { + versionChecker = nullptr; + appearanceEditorWindow = nullptr; + utf8Window = nullptr; + svgPathWindow = nullptr; + + mainWindowList.forceCloseAllWindows(); + openDocumentManager.clear(); + commandManager = nullptr; + settings = nullptr; + + #if JUCE_MAC + MenuBarModel::setMacMainMenu (nullptr); + #endif + menuModel = nullptr; + + LookAndFeel::setDefaultLookAndFeel (nullptr); + + if (! isRunningCommandLine) + Logger::writeToLog ("Shutdown"); + + deleteLogger(); + } + + //============================================================================== + void systemRequestedQuit() override + { + if (ModalComponentManager::getInstance()->cancelAllModalComponents()) + { + new AsyncQuitRetrier(); + } + else + { + if (closeAllMainWindows()) + quit(); + } + } + + //============================================================================== + const String getApplicationName() override { return "Introjucer"; } + const String getApplicationVersion() override { return ProjectInfo::versionString; } + + bool moreThanOneInstanceAllowed() override + { + return true; // this is handled manually in initialise() + } + + void anotherInstanceStarted (const String& commandLine) override + { + openFile (File (commandLine.unquoted())); + } + + static IntrojucerApp& getApp() + { + IntrojucerApp* const app = dynamic_cast (JUCEApplication::getInstance()); + jassert (app != nullptr); + return *app; + } + + static ApplicationCommandManager& getCommandManager() + { + ApplicationCommandManager* cm = IntrojucerApp::getApp().commandManager; + jassert (cm != nullptr); + return *cm; + } + + //============================================================================== + class MainMenuModel : public MenuBarModel + { + public: + MainMenuModel() + { + setApplicationCommandManagerToWatch (&getCommandManager()); + } + + StringArray getMenuBarNames() override + { + return getApp().getMenuNames(); + } + + PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName) override + { + PopupMenu menu; + getApp().createMenu (menu, menuName); + return menu; + } + + void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) override + { + getApp().handleMainMenuCommand (menuItemID); + } + }; + + enum + { + recentProjectsBaseID = 100, + activeDocumentsBaseID = 300, + colourSchemeBaseID = 1000 + }; + + virtual StringArray getMenuNames() + { + const char* const names[] = { "File", "Edit", "View", "Window", "GUI Editor", "Tools", nullptr }; + return StringArray (names); + } + + virtual void createMenu (PopupMenu& menu, const String& menuName) + { + if (menuName == "File") createFileMenu (menu); + else if (menuName == "Edit") createEditMenu (menu); + else if (menuName == "View") createViewMenu (menu); + else if (menuName == "Window") createWindowMenu (menu); + else if (menuName == "Tools") createToolsMenu (menu); + else if (menuName == "GUI Editor") createGUIEditorMenu (menu); + else jassertfalse; // names have changed? + } + + virtual void createFileMenu (PopupMenu& menu) + { + menu.addCommandItem (commandManager, CommandIDs::newProject); + menu.addSeparator(); + menu.addCommandItem (commandManager, CommandIDs::open); + + PopupMenu recentFiles; + settings->recentFiles.createPopupMenuItems (recentFiles, recentProjectsBaseID, true, true); + menu.addSubMenu ("Open Recent", recentFiles); + + menu.addSeparator(); + menu.addCommandItem (commandManager, CommandIDs::closeDocument); + menu.addCommandItem (commandManager, CommandIDs::saveDocument); + menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs); + menu.addCommandItem (commandManager, CommandIDs::saveAll); + menu.addSeparator(); + menu.addCommandItem (commandManager, CommandIDs::closeProject); + menu.addCommandItem (commandManager, CommandIDs::saveProject); + menu.addSeparator(); + menu.addCommandItem (commandManager, CommandIDs::openInIDE); + menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE); + + #if ! JUCE_MAC + menu.addSeparator(); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit); + #endif + } + + virtual void createEditMenu (PopupMenu& menu) + { + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::undo); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::redo); + menu.addSeparator(); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll); + menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll); + menu.addSeparator(); + menu.addCommandItem (commandManager, CommandIDs::showFindPanel); + menu.addCommandItem (commandManager, CommandIDs::findSelection); + menu.addCommandItem (commandManager, CommandIDs::findNext); + menu.addCommandItem (commandManager, CommandIDs::findPrevious); + } + + virtual void createViewMenu (PopupMenu& menu) + { + menu.addCommandItem (commandManager, CommandIDs::showFilePanel); + menu.addCommandItem (commandManager, CommandIDs::showConfigPanel); + menu.addCommandItem (commandManager, CommandIDs::showProjectSettings); + menu.addCommandItem (commandManager, CommandIDs::showProjectModules); + menu.addSeparator(); + createColourSchemeItems (menu); + } + + void createColourSchemeItems (PopupMenu& menu) + { + menu.addCommandItem (commandManager, CommandIDs::showAppearanceSettings); + + const StringArray presetSchemes (settings->appearance.getPresetSchemes()); + + if (presetSchemes.size() > 0) + { + PopupMenu schemes; + + for (int i = 0; i < presetSchemes.size(); ++i) + schemes.addItem (colourSchemeBaseID + i, presetSchemes[i]); + + menu.addSubMenu ("Colour Scheme", schemes); + } + } + + virtual void createWindowMenu (PopupMenu& menu) + { + menu.addCommandItem (commandManager, CommandIDs::closeWindow); + menu.addSeparator(); + + menu.addCommandItem (commandManager, CommandIDs::goToPreviousDoc); + menu.addCommandItem (commandManager, CommandIDs::goToNextDoc); + menu.addCommandItem (commandManager, CommandIDs::goToCounterpart); + menu.addSeparator(); + + const int numDocs = jmin (50, openDocumentManager.getNumOpenDocuments()); + + for (int i = 0; i < numDocs; ++i) + { + OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument(i); + menu.addItem (activeDocumentsBaseID + i, doc->getName()); + } + + menu.addSeparator(); + menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments); + } + + virtual void createToolsMenu (PopupMenu& menu) + { + menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool); + menu.addCommandItem (commandManager, CommandIDs::showSVGPathTool); + menu.addCommandItem (commandManager, CommandIDs::showTranslationTool); + } + + virtual void handleMainMenuCommand (int menuItemID) + { + if (menuItemID >= recentProjectsBaseID && menuItemID < recentProjectsBaseID + 100) + { + // open a file from the "recent files" menu + openFile (settings->recentFiles.getFile (menuItemID - recentProjectsBaseID)); + } + else if (menuItemID >= activeDocumentsBaseID && menuItemID < activeDocumentsBaseID + 200) + { + if (OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument (menuItemID - activeDocumentsBaseID)) + mainWindowList.openDocument (doc, true); + else + jassertfalse; + } + else if (menuItemID >= colourSchemeBaseID && menuItemID < colourSchemeBaseID + 200) + { + settings->appearance.selectPresetScheme (menuItemID - colourSchemeBaseID); + } + else + { + handleGUIEditorMenuCommand (menuItemID); + } + } + + //============================================================================== + void getAllCommands (Array & commands) override + { + JUCEApplication::getAllCommands (commands); + + const CommandID ids[] = { CommandIDs::newProject, + CommandIDs::open, + CommandIDs::closeAllDocuments, + CommandIDs::saveAll, + CommandIDs::showAppearanceSettings, + CommandIDs::showUTF8Tool, + CommandIDs::showSVGPathTool }; + + commands.addArray (ids, numElementsInArray (ids)); + } + + void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override + { + switch (commandID) + { + case CommandIDs::newProject: + result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0); + result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0)); + break; + + case CommandIDs::open: + result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0); + result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0)); + break; + + case CommandIDs::showAppearanceSettings: + result.setInfo ("Fonts and Colours...", "Shows the appearance settings window.", CommandCategories::general, 0); + break; + + case CommandIDs::closeAllDocuments: + result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0); + result.setActive (openDocumentManager.getNumOpenDocuments() > 0); + break; + + case CommandIDs::saveAll: + result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0); + result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::altModifier, 0)); + break; + + case CommandIDs::showUTF8Tool: + result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0); + break; + + case CommandIDs::showSVGPathTool: + result.setInfo ("SVG Path Helper", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0); + break; + + default: + JUCEApplication::getCommandInfo (commandID, result); + break; + } + } + + bool perform (const InvocationInfo& info) override + { + switch (info.commandID) + { + case CommandIDs::newProject: createNewProject(); break; + case CommandIDs::open: askUserToOpenFile(); break; + case CommandIDs::saveAll: openDocumentManager.saveAll(); break; + case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; + case CommandIDs::showUTF8Tool: showUTF8ToolWindow (utf8Window); break; + case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow (svgPathWindow); break; + + case CommandIDs::showAppearanceSettings: AppearanceSettings::showEditorWindow (appearanceEditorWindow); break; + default: return JUCEApplication::perform (info); + } + + return true; + } + + //============================================================================== + void createNewProject() + { + MainWindow* mw = mainWindowList.getOrCreateEmptyWindow(); + mw->showNewProjectWizard(); + mainWindowList.avoidSuperimposedWindows (mw); + } + + virtual void updateNewlyOpenedProject (Project&) {} + + void askUserToOpenFile() + { + FileChooser fc ("Open File"); + + if (fc.browseForFileToOpen()) + openFile (fc.getResult()); + } + + bool openFile (const File& file) + { + return mainWindowList.openFile (file); + } + + bool closeAllDocuments (bool askUserToSave) + { + return openDocumentManager.closeAll (askUserToSave); + } + + virtual bool closeAllMainWindows() + { + return mainWindowList.askAllWindowsToClose(); + } + + //============================================================================== + void initialiseLogger (const char* filePrefix) + { + if (logger == nullptr) + { + logger = FileLogger::createDateStampedLogger (getLogFolderName(), filePrefix, ".txt", + getApplicationName() + " " + getApplicationVersion() + + " --- Build date: " __DATE__); + Logger::setCurrentLogger (logger); + } + } + + struct FileWithTime + { + FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {} + FileWithTime() {} + + bool operator< (const FileWithTime& other) const { return time < other.time; } + bool operator== (const FileWithTime& other) const { return time == other.time; } + + File file; + Time time; + }; + + void deleteLogger() + { + const int maxNumLogFilesToKeep = 50; + + Logger::setCurrentLogger (nullptr); + + if (logger != nullptr) + { + Array logFiles; + logger->getLogFile().getParentDirectory().findChildFiles (logFiles, File::findFiles, false); + + if (logFiles.size() > maxNumLogFilesToKeep) + { + Array files; + + for (int i = 0; i < logFiles.size(); ++i) + files.addUsingDefaultSort (logFiles.getReference(i)); + + for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i) + files.getReference(i).file.deleteFile(); + } + } + + logger = nullptr; + } + + virtual void doExtraInitialisation() {} + virtual void addExtraConfigItems (Project&, TreeViewItem&) {} + + #if JUCE_LINUX + virtual String getLogFolderName() const { return "~/.config/Introjucer/Logs"; } + #else + virtual String getLogFolderName() const { return "com.juce.introjucer"; } + #endif + + virtual PropertiesFile::Options getPropertyFileOptionsFor (const String& filename) + { + PropertiesFile::Options options; + options.applicationName = filename; + options.filenameSuffix = "settings"; + options.osxLibrarySubFolder = "Application Support"; + #if JUCE_LINUX + options.folderName = "~/.config/Introjucer"; + #else + options.folderName = "Introjucer"; + #endif + + return options; + } + + virtual Component* createProjectContentComponent() const + { + return new ProjectContentComponent(); + } + + //============================================================================== + IntrojucerLookAndFeel lookAndFeel; + + ScopedPointer settings; + ScopedPointer icons; + + ScopedPointer menuModel; + + MainWindowList mainWindowList; + OpenDocumentManager openDocumentManager; + ScopedPointer commandManager; + + ScopedPointer appearanceEditorWindow, utf8Window, svgPathWindow; + + ScopedPointer logger; + + bool isRunningCommandLine; + +private: + ScopedPointer versionChecker; + + class AsyncQuitRetrier : private Timer + { + public: + AsyncQuitRetrier() { startTimer (500); } + + void timerCallback() override + { + stopTimer(); + delete this; + + if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance()) + app->systemRequestedQuit(); + } + + JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier) + }; + + void initCommandManager() + { + commandManager = new ApplicationCommandManager(); + commandManager->registerAllCommandsForTarget (this); + + { + CodeDocument doc; + CppCodeEditorComponent ed (File::nonexistent, doc); + commandManager->registerAllCommandsForTarget (&ed); + } + + registerGUIEditorCommands(); + } +}; + + +#endif // __JUCER_APPLICATION_JUCEHEADER__ diff --git a/extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp b/extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp index c6116d9303..5ff41decb7 100644 --- a/extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp +++ b/extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp @@ -1,721 +1,721 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2013 - Raw Material Software Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -#include "jucer_ProjectExporter.h" -#include "jucer_ProjectSaver.h" - -#include "jucer_ProjectExport_Make.h" -#include "jucer_ProjectExport_MSVC.h" -#include "jucer_ProjectExport_XCode.h" -#include "jucer_ProjectExport_Android.h" -#include "jucer_ProjectExport_CodeBlocks.h" - -//============================================================================== -static void addType (Array& list, - const char* name, const void* iconData, int iconDataSize) -{ - ProjectExporter::ExporterTypeInfo type = { name, iconData, iconDataSize }; - list.add (type); -} - -Array ProjectExporter::getExporterTypes() -{ - Array types; - - addType (types, XCodeProjectExporter::getNameMac(), BinaryData::projectIconXcode_png, BinaryData::projectIconXcode_pngSize); - addType (types, XCodeProjectExporter::getNameiOS(), BinaryData::projectIconXcodeIOS_png, BinaryData::projectIconXcodeIOS_pngSize); - addType (types, MSVCProjectExporterVC2013::getName(), BinaryData::projectIconVisualStudio13_png, BinaryData::projectIconVisualStudio13_pngSize); - addType (types, MSVCProjectExporterVC2012::getName(), BinaryData::projectIconVisualStudio12_png, BinaryData::projectIconVisualStudio12_pngSize); - addType (types, MSVCProjectExporterVC2010::getName(), BinaryData::projectIconVisualStudio10_png, BinaryData::projectIconVisualStudio10_pngSize); - addType (types, MSVCProjectExporterVC2008::getName(), BinaryData::projectIconVisualStudio08_png, BinaryData::projectIconVisualStudio08_pngSize); - addType (types, MSVCProjectExporterVC2005::getName(), BinaryData::projectIconVisualStudio05_png, BinaryData::projectIconVisualStudio05_pngSize); - addType (types, MakefileProjectExporter::getNameLinux(), BinaryData::projectIconLinuxMakefile_png, BinaryData::projectIconLinuxMakefile_pngSize); - addType (types, AndroidProjectExporter::getNameAndroid(), BinaryData::projectIconAndroid_png, BinaryData::projectIconAndroid_pngSize); - addType (types, CodeBlocksProjectExporter::getNameCodeBlocks(), BinaryData::projectIconCodeblocks_png, BinaryData::projectIconCodeblocks_pngSize); - - return types; -} - -StringArray ProjectExporter::getExporterNames() -{ - StringArray s; - Array types (getExporterTypes()); - - for (int i = 0; i < types.size(); ++i) - s.add (types.getReference(i).name); - - return s; -} - -String ProjectExporter::getCurrentPlatformExporterName() -{ - #if JUCE_MAC - return XCodeProjectExporter::getNameMac(); - #elif JUCE_WINDOWS - return MSVCProjectExporterVC2010::getName(); - #elif JUCE_LINUX - return MakefileProjectExporter::getNameLinux(); - #else - #error // huh? - #endif -} - -ProjectExporter* ProjectExporter::createNewExporter (Project& project, const int index) -{ - ProjectExporter* exp = nullptr; - - switch (index) - { - case 0: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter ::getValueTreeTypeName (false)), false); break; - case 1: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter ::getValueTreeTypeName (true)), true); break; - case 2: exp = new MSVCProjectExporterVC2013 (project, ValueTree (MSVCProjectExporterVC2013::getValueTreeTypeName())); break; - case 3: exp = new MSVCProjectExporterVC2012 (project, ValueTree (MSVCProjectExporterVC2012::getValueTreeTypeName())); break; - case 4: exp = new MSVCProjectExporterVC2010 (project, ValueTree (MSVCProjectExporterVC2010::getValueTreeTypeName())); break; - case 5: exp = new MSVCProjectExporterVC2012 (project, ValueTree (MSVCProjectExporterVC2012::getValueTreeTypeName())); break; - case 6: exp = new MSVCProjectExporterVC2013 (project, ValueTree (MSVCProjectExporterVC2013::getValueTreeTypeName())); break; - case 7: exp = new MSVCProjectExporterVC2015 (project, ValueTree (MSVCProjectExporterVC2015::getValueTreeTypeName())); break; - case 8: exp = new MakefileProjectExporter (project, ValueTree (MakefileProjectExporter ::getValueTreeTypeName())); break; - case 9: exp = new AndroidProjectExporter (project, ValueTree (AndroidProjectExporter ::getValueTreeTypeName())); break; - case 10: exp = new CodeBlocksProjectExporter (project, ValueTree (CodeBlocksProjectExporter::getValueTreeTypeName())); break; - - default: jassertfalse; return 0; - } - - exp->createDefaultConfigs(); - exp->createDefaultModulePaths(); - - return exp; -} - -ProjectExporter* ProjectExporter::createNewExporter (Project& project, const String& name) -{ - return createNewExporter (project, getExporterNames().indexOf (name)); -} - -ProjectExporter* ProjectExporter::createExporter (Project& project, const ValueTree& settings) -{ - ProjectExporter* exp = MSVCProjectExporterVC2005::createForSettings (project, settings); - if (exp == nullptr) exp = MSVCProjectExporterVC2008::createForSettings (project, settings); - if (exp == nullptr) exp = MSVCProjectExporterVC2010::createForSettings (project, settings); - if (exp == nullptr) exp = MSVCProjectExporterVC2012::createForSettings (project, settings); - if (exp == nullptr) exp = MSVCProjectExporterVC2013::createForSettings (project, settings); - if (exp == nullptr) exp = MSVCProjectExporterVC2015::createForSettings (project, settings); - if (exp == nullptr) exp = XCodeProjectExporter ::createForSettings (project, settings); - if (exp == nullptr) exp = MakefileProjectExporter ::createForSettings (project, settings); - if (exp == nullptr) exp = AndroidProjectExporter ::createForSettings (project, settings); - if (exp == nullptr) exp = CodeBlocksProjectExporter::createForSettings (project, settings); - - jassert (exp != nullptr); - return exp; -} - -bool ProjectExporter::canProjectBeLaunched (Project* project) -{ - if (project != nullptr) - { - const char* types[] = - { - #if JUCE_MAC - XCodeProjectExporter::getValueTreeTypeName (false), - XCodeProjectExporter::getValueTreeTypeName (true), - #elif JUCE_WINDOWS - MSVCProjectExporterVC2005::getValueTreeTypeName(), - MSVCProjectExporterVC2008::getValueTreeTypeName(), - MSVCProjectExporterVC2010::getValueTreeTypeName(), - MSVCProjectExporterVC2012::getValueTreeTypeName(), - MSVCProjectExporterVC2013::getValueTreeTypeName(), - MSVCProjectExporterVC2015::getValueTreeTypeName(), - #elif JUCE_LINUX - // (this doesn't currently launch.. not really sure what it would do on linux) - //MakefileProjectExporter::getValueTreeTypeName(), - #endif - - nullptr - }; - - for (const char** type = types; *type != nullptr; ++type) - if (project->getExporters().getChildWithName (*type).isValid()) - return true; - } - - return false; -} - -//============================================================================== -ProjectExporter::ProjectExporter (Project& p, const ValueTree& state) - : xcodeIsBundle (false), - xcodeCreatePList (false), - xcodeCanUseDwarf (true), - makefileIsDLL (false), - msvcIsDLL (false), - msvcIsWindowsSubsystem (true), - settings (state), - project (p), - projectType (p.getProjectType()), - projectName (p.getTitle()), - projectFolder (p.getProjectFolder()), - modulesGroup (nullptr) -{ -} - -ProjectExporter::~ProjectExporter() -{ -} - -File ProjectExporter::getTargetFolder() const -{ - return project.resolveFilename (getTargetLocationString()); -} - -RelativePath ProjectExporter::rebaseFromProjectFolderToBuildTarget (const RelativePath& path) const -{ - return path.rebased (project.getProjectFolder(), getTargetFolder(), RelativePath::buildTargetFolder); -} - -bool ProjectExporter::shouldFileBeCompiledByDefault (const RelativePath& file) const -{ - return file.hasFileExtension (cOrCppFileExtensions) - || file.hasFileExtension (asmFileExtensions); -} - -void ProjectExporter::createPropertyEditors (PropertyListBuilder& props) -{ - props.add (new TextPropertyComponent (getTargetLocationValue(), "Target Project Folder", 2048, false), - "The location of the folder in which the " + name + " project will be created. " - "This path can be absolute, but it's much more sensible to make it relative to the jucer project directory."); - - OwnedArray modules; - project.getModules().createRequiredModules (modules); - - for (int i = 0; i < modules.size(); ++i) - modules.getUnchecked(i)->createPropertyEditors (*this, props); - - props.add (new TextPropertyComponent (getExporterPreprocessorDefs(), "Extra Preprocessor Definitions", 32768, true), - "Extra preprocessor definitions. Use the form \"NAME1=value NAME2=value\", using whitespace, commas, " - "or new-lines to separate the items - to include a space or comma in a definition, precede it with a backslash."); - - props.add (new TextPropertyComponent (getExtraCompilerFlags(), "Extra compiler flags", 8192, true), - "Extra command-line flags to be passed to the compiler. This string can contain references to preprocessor definitions in the " - "form ${NAME_OF_DEFINITION}, which will be replaced with their values."); - - props.add (new TextPropertyComponent (getExtraLinkerFlags(), "Extra linker flags", 8192, true), - "Extra command-line flags to be passed to the linker. You might want to use this for adding additional libraries. " - "This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values."); - - props.add (new TextPropertyComponent (getExternalLibraries(), "External libraries to link", 8192, true), - "Additional libraries to link (one per line). You should not add any platform specific decoration to these names. " - "This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values."); - - { - OwnedArray images; - project.findAllImageItems (images); - - StringArray choices; - Array ids; - - choices.add (""); - ids.add (var::null); - choices.add (String::empty); - ids.add (var::null); - - for (int i = 0; i < images.size(); ++i) - { - choices.add (images.getUnchecked(i)->getName()); - ids.add (images.getUnchecked(i)->getID()); - } - - props.add (new ChoicePropertyComponent (getSmallIconImageItemID(), "Icon (small)", choices, ids), - "Sets an icon to use for the executable."); - - props.add (new ChoicePropertyComponent (getBigIconImageItemID(), "Icon (large)", choices, ids), - "Sets an icon to use for the executable."); - } - - createExporterProperties (props); - - props.add (new TextPropertyComponent (getUserNotes(), "Notes", 32768, true), - "Extra comments: This field is not used for code or project generation, it's just a space where you can express your thoughts."); -} - -StringPairArray ProjectExporter::getAllPreprocessorDefs (const ProjectExporter::BuildConfiguration& config) const -{ - StringPairArray defs (mergePreprocessorDefs (config.getAllPreprocessorDefs(), - parsePreprocessorDefs (getExporterPreprocessorDefsString()))); - addDefaultPreprocessorDefs (defs); - return defs; -} - -StringPairArray ProjectExporter::getAllPreprocessorDefs() const -{ - StringPairArray defs (mergePreprocessorDefs (project.getPreprocessorDefs(), - parsePreprocessorDefs (getExporterPreprocessorDefsString()))); - addDefaultPreprocessorDefs (defs); - return defs; -} - -void ProjectExporter::addDefaultPreprocessorDefs (StringPairArray& defs) const -{ - defs.set (getExporterIdentifierMacro(), "1"); - defs.set ("JUCE_APP_VERSION", project.getVersionString()); - defs.set ("JUCE_APP_VERSION_HEX", project.getVersionAsHex()); -} - -String ProjectExporter::replacePreprocessorTokens (const ProjectExporter::BuildConfiguration& config, const String& sourceString) const -{ - return replacePreprocessorDefs (getAllPreprocessorDefs (config), sourceString); -} - -void ProjectExporter::copyMainGroupFromProject() -{ - jassert (itemGroups.size() == 0); - itemGroups.add (project.getMainGroup().createCopy()); -} - -Project::Item& ProjectExporter::getModulesGroup() -{ - if (modulesGroup == nullptr) - { - jassert (itemGroups.size() > 0); // must call copyMainGroupFromProject before this. - itemGroups.add (Project::Item::createGroup (project, "Juce Modules", "__modulesgroup__")); - modulesGroup = &(itemGroups.getReference (itemGroups.size() - 1)); - } - - return *modulesGroup; -} - -void ProjectExporter::addToExtraSearchPaths (const RelativePath& pathFromProjectFolder) -{ - RelativePath localPath (rebaseFromProjectFolderToBuildTarget (pathFromProjectFolder)); - - const String path (isVisualStudio() ? localPath.toWindowsStyle() : localPath.toUnixStyle()); - extraSearchPaths.addIfNotAlreadyThere (path, false); -} - -Value ProjectExporter::getPathForModuleValue (const String& moduleID) -{ - UndoManager* um = project.getUndoManagerFor (settings); - - ValueTree paths (settings.getOrCreateChildWithName (Ids::MODULEPATHS, um)); - ValueTree m (paths.getChildWithProperty (Ids::ID, moduleID)); - - if (! m.isValid()) - { - m = ValueTree (Ids::MODULEPATH); - m.setProperty (Ids::ID, moduleID, um); - paths.addChild (m, -1, um); - } - - return m.getPropertyAsValue (Ids::path, um); -} - -String ProjectExporter::getPathForModuleString (const String& moduleID) const -{ - return settings.getChildWithName (Ids::MODULEPATHS) - .getChildWithProperty (Ids::ID, moduleID) [Ids::path].toString(); -} - -void ProjectExporter::removePathForModule (const String& moduleID) -{ - ValueTree paths (settings.getChildWithName (Ids::MODULEPATHS)); - ValueTree m (paths.getChildWithProperty (Ids::ID, moduleID)); - paths.removeChild (m, project.getUndoManagerFor (settings)); -} - -RelativePath ProjectExporter::getModuleFolderRelativeToProject (const String& moduleID, ProjectSaver& projectSaver) const -{ - if (project.getModules().shouldCopyModuleFilesLocally (moduleID).getValue()) - return RelativePath (project.getRelativePathForFile (projectSaver.getLocalModuleFolder (moduleID)), - RelativePath::projectFolder); - - String path (getPathForModuleString (moduleID)); - - if (path.isEmpty()) - return getLegacyModulePath (moduleID).getChildFile (moduleID); - - return RelativePath (path, RelativePath::projectFolder).getChildFile (moduleID); -} - -String ProjectExporter::getLegacyModulePath() const -{ - return getSettingString ("juceFolder"); -} - -RelativePath ProjectExporter::getLegacyModulePath (const String& moduleID) const -{ - if (project.getModules().state.getChildWithProperty (Ids::ID, moduleID) ["useLocalCopy"]) - return RelativePath (project.getRelativePathForFile (project.getGeneratedCodeFolder() - .getChildFile ("modules") - .getChildFile (moduleID)), RelativePath::projectFolder); - - String oldJucePath (getLegacyModulePath()); - - if (oldJucePath.isEmpty()) - return RelativePath(); - - RelativePath p (oldJucePath, RelativePath::projectFolder); - if (p.getFileName() != "modules") - p = p.getChildFile ("modules"); - - return p.getChildFile (moduleID); -} - -void ProjectExporter::updateOldModulePaths() -{ - String oldPath (getLegacyModulePath()); - - if (oldPath.isNotEmpty()) - { - for (int i = project.getModules().getNumModules(); --i >= 0;) - { - String modID (project.getModules().getModuleID(i)); - getPathForModuleValue (modID) = getLegacyModulePath (modID).getParentDirectory().toUnixStyle(); - } - - settings.removeProperty ("juceFolder", nullptr); - } -} - -static bool areCompatibleExporters (const ProjectExporter& p1, const ProjectExporter& p2) -{ - return (p1.isVisualStudio() && p2.isVisualStudio()) - || (p1.isXcode() && p2.isXcode()) - || (p1.isLinux() && p2.isLinux()) - || (p1.isAndroid() && p2.isAndroid()) - || (p1.isCodeBlocks() && p2.isCodeBlocks()); -} - -void ProjectExporter::createDefaultModulePaths() -{ - for (Project::ExporterIterator exporter (project); exporter.next();) - { - if (areCompatibleExporters (*this, *exporter)) - { - for (int i = project.getModules().getNumModules(); --i >= 0;) - { - String modID (project.getModules().getModuleID(i)); - getPathForModuleValue (modID) = exporter->getPathForModuleValue (modID).getValue(); - } - - return; - } - } - - for (Project::ExporterIterator exporter (project); exporter.next();) - { - if (exporter->canLaunchProject()) - { - for (int i = project.getModules().getNumModules(); --i >= 0;) - { - String modID (project.getModules().getModuleID(i)); - getPathForModuleValue (modID) = exporter->getPathForModuleValue (modID).getValue(); - } - - return; - } - } - - for (int i = project.getModules().getNumModules(); --i >= 0;) - { - String modID (project.getModules().getModuleID(i)); - getPathForModuleValue (modID) = "../../juce"; - } -} - -//============================================================================== -ValueTree ProjectExporter::getConfigurations() const -{ - return settings.getChildWithName (Ids::CONFIGURATIONS); -} - -int ProjectExporter::getNumConfigurations() const -{ - return getConfigurations().getNumChildren(); -} - -ProjectExporter::BuildConfiguration::Ptr ProjectExporter::getConfiguration (int index) const -{ - return createBuildConfig (getConfigurations().getChild (index)); -} - -bool ProjectExporter::hasConfigurationNamed (const String& nameToFind) const -{ - const ValueTree configs (getConfigurations()); - for (int i = configs.getNumChildren(); --i >= 0;) - if (configs.getChild(i) [Ids::name].toString() == nameToFind) - return true; - - return false; -} - -String ProjectExporter::getUniqueConfigName (String nm) const -{ - String nameRoot (nm); - while (CharacterFunctions::isDigit (nameRoot.getLastCharacter())) - nameRoot = nameRoot.dropLastCharacters (1); - - nameRoot = nameRoot.trim(); - - int suffix = 2; - while (hasConfigurationNamed (name)) - nm = nameRoot + " " + String (suffix++); - - return nm; -} - -void ProjectExporter::addNewConfiguration (const BuildConfiguration* configToCopy) -{ - const String configName (getUniqueConfigName (configToCopy != nullptr ? configToCopy->config [Ids::name].toString() - : "New Build Configuration")); - - ValueTree configs (getConfigurations()); - - if (! configs.isValid()) - { - settings.addChild (ValueTree (Ids::CONFIGURATIONS), 0, project.getUndoManagerFor (settings)); - configs = getConfigurations(); - } - - ValueTree newConfig (Ids::CONFIGURATION); - if (configToCopy != nullptr) - newConfig = configToCopy->config.createCopy(); - - newConfig.setProperty (Ids::name, configName, 0); - - configs.addChild (newConfig, -1, project.getUndoManagerFor (configs)); -} - -void ProjectExporter::BuildConfiguration::removeFromExporter() -{ - ValueTree configs (config.getParent()); - configs.removeChild (config, project.getUndoManagerFor (configs)); -} - -void ProjectExporter::createDefaultConfigs() -{ - settings.getOrCreateChildWithName (Ids::CONFIGURATIONS, nullptr); - - for (int i = 0; i < 2; ++i) - { - addNewConfiguration (nullptr); - BuildConfiguration::Ptr config (getConfiguration (i)); - - const bool debugConfig = i == 0; - - config->getNameValue() = debugConfig ? "Debug" : "Release"; - config->isDebugValue() = debugConfig; - config->getOptimisationLevel() = debugConfig ? optimisationOff : optimiseMinSize; - config->getTargetBinaryName() = project.getProjectFilenameRoot(); - } -} - -Drawable* ProjectExporter::getBigIcon() const -{ - return project.getMainGroup().findItemWithID (settings [Ids::bigIcon]).loadAsImageFile(); -} - -Drawable* ProjectExporter::getSmallIcon() const -{ - return project.getMainGroup().findItemWithID (settings [Ids::smallIcon]).loadAsImageFile(); -} - -Image ProjectExporter::getBestIconForSize (int size, bool returnNullIfNothingBigEnough) const -{ - Drawable* im = nullptr; - - ScopedPointer im1 (getSmallIcon()); - ScopedPointer im2 (getBigIcon()); - - if (im1 != nullptr && im2 != nullptr) - { - if (im1->getWidth() >= size && im2->getWidth() >= size) - im = im1->getWidth() < im2->getWidth() ? im1 : im2; - else if (im1->getWidth() >= size) - im = im1; - else if (im2->getWidth() >= size) - im = im2; - } - else - { - im = im1 != nullptr ? im1 : im2; - } - - if (im == nullptr) - return Image(); - - if (returnNullIfNothingBigEnough && im->getWidth() < size && im->getHeight() < size) - return Image(); - - return rescaleImageForIcon (*im, size); -} - -Image ProjectExporter::rescaleImageForIcon (Drawable& d, const int size) -{ - if (DrawableImage* drawableImage = dynamic_cast (&d)) - { - Image im = SoftwareImageType().convert (drawableImage->getImage()); - - if (size == im.getWidth() && size == im.getHeight()) - return im; - - // (scale it down in stages for better resampling) - while (im.getWidth() > 2 * size && im.getHeight() > 2 * size) - im = im.rescaled (im.getWidth() / 2, - im.getHeight() / 2); - - Image newIm (Image::ARGB, size, size, true, SoftwareImageType()); - Graphics g (newIm); - g.drawImageWithin (im, 0, 0, size, size, - RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false); - return newIm; - } - - Image im (Image::ARGB, size, size, true, SoftwareImageType()); - Graphics g (im); - d.drawWithin (g, im.getBounds().toFloat(), RectanglePlacement::centred, 1.0f); - return im; -} - - -//============================================================================== -ProjectExporter::ConfigIterator::ConfigIterator (ProjectExporter& e) - : index (-1), exporter (e) -{ -} - -bool ProjectExporter::ConfigIterator::next() -{ - if (++index >= exporter.getNumConfigurations()) - return false; - - config = exporter.getConfiguration (index); - return true; -} - -ProjectExporter::ConstConfigIterator::ConstConfigIterator (const ProjectExporter& exporter_) - : index (-1), exporter (exporter_) -{ -} - -bool ProjectExporter::ConstConfigIterator::next() -{ - if (++index >= exporter.getNumConfigurations()) - return false; - - config = exporter.getConfiguration (index); - return true; -} - -//============================================================================== -ProjectExporter::BuildConfiguration::BuildConfiguration (Project& p, const ValueTree& configNode) - : config (configNode), project (p) -{ -} - -ProjectExporter::BuildConfiguration::~BuildConfiguration() -{ -} - -String ProjectExporter::BuildConfiguration::getGCCOptimisationFlag() const -{ - switch (getOptimisationLevelInt()) - { - case optimiseMaxSpeed: return "3"; - case optimiseMinSize: return "s"; - default: return "0"; - } -} - -void ProjectExporter::BuildConfiguration::createPropertyEditors (PropertyListBuilder& props) -{ - props.add (new TextPropertyComponent (getNameValue(), "Name", 96, false), - "The name of this configuration."); - - props.add (new BooleanPropertyComponent (isDebugValue(), "Debug mode", "Debugging enabled"), - "If enabled, this means that the configuration should be built with debug synbols."); - - static const char* optimisationLevels[] = { "No optimisation", "Minimise size", "Maximise speed", 0 }; - const int optimisationLevelValues[] = { optimisationOff, optimiseMinSize, optimiseMaxSpeed, 0 }; - props.add (new ChoicePropertyComponent (getOptimisationLevel(), "Optimisation", - StringArray (optimisationLevels), Array (optimisationLevelValues)), - "The optimisation level for this configuration"); - - props.add (new TextPropertyComponent (getTargetBinaryName(), "Binary name", 256, false), - "The filename to use for the destination binary executable file. If you don't add a suffix to this name, " - "a suitable platform-specific suffix will be added automatically."); - - props.add (new TextPropertyComponent (getTargetBinaryRelativePath(), "Binary location", 1024, false), - "The folder in which the finished binary should be placed. Leave this blank to cause the binary to be placed " - "in its default location in the build folder."); - - props.addSearchPathProperty (getHeaderSearchPathValue(), "Header search paths", "Extra header search paths."); - props.addSearchPathProperty (getLibrarySearchPathValue(), "Extra library search paths", "Extra library search paths."); - - props.add (new TextPropertyComponent (getBuildConfigPreprocessorDefs(), "Preprocessor definitions", 32768, true), - "Extra preprocessor definitions. Use the form \"NAME1=value NAME2=value\", using whitespace, commas, or " - "new-lines to separate the items - to include a space or comma in a definition, precede it with a backslash."); - - createConfigProperties (props); - - props.add (new TextPropertyComponent (getUserNotes(), "Notes", 32768, true), - "Extra comments: This field is not used for code or project generation, it's just a space where you can express your thoughts."); -} - -StringPairArray ProjectExporter::BuildConfiguration::getAllPreprocessorDefs() const -{ - return mergePreprocessorDefs (project.getPreprocessorDefs(), - parsePreprocessorDefs (getBuildConfigPreprocessorDefsString())); -} - -StringArray ProjectExporter::BuildConfiguration::getHeaderSearchPaths() const -{ - return getSearchPathsFromString (getHeaderSearchPathString()); -} - -StringArray ProjectExporter::BuildConfiguration::getLibrarySearchPaths() const -{ - return getSearchPathsFromString (getLibrarySearchPathString()); -} - -String ProjectExporter::BuildConfiguration::getGCCLibraryPathFlags() const -{ - String s; - const StringArray libraryPaths (getLibrarySearchPaths()); - - for (int i = 0; i < libraryPaths.size(); ++i) - s << " -L" << addQuotesIfContainsSpaces (libraryPaths[i]); - - return s; -} - -String ProjectExporter::getExternalLibraryFlags (const BuildConfiguration& config) const -{ - StringArray libraries; - libraries.addTokens (getExternalLibrariesString(), ";\n", "\"'"); - libraries.removeEmptyStrings (true); - - if (libraries.size() != 0) - return replacePreprocessorTokens (config, "-l" + libraries.joinIntoString (" -l")).trim(); - - return String::empty; -} +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2013 - Raw Material Software Ltd. + + Permission is granted to use this software under the terms of either: + a) the GPL v2 (or any later version) + b) the Affero GPL v3 + + Details of these licenses can be found at: www.gnu.org/licenses + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.juce.com for more information. + + ============================================================================== +*/ + +#include "jucer_ProjectExporter.h" +#include "jucer_ProjectSaver.h" + +#include "jucer_ProjectExport_Make.h" +#include "jucer_ProjectExport_MSVC.h" +#include "jucer_ProjectExport_XCode.h" +#include "jucer_ProjectExport_Android.h" +#include "jucer_ProjectExport_CodeBlocks.h" + +//============================================================================== +static void addType (Array& list, + const char* name, const void* iconData, int iconDataSize) +{ + ProjectExporter::ExporterTypeInfo type = { name, iconData, iconDataSize }; + list.add (type); +} + +Array ProjectExporter::getExporterTypes() +{ + Array types; + + addType (types, XCodeProjectExporter::getNameMac(), BinaryData::projectIconXcode_png, BinaryData::projectIconXcode_pngSize); + addType (types, XCodeProjectExporter::getNameiOS(), BinaryData::projectIconXcodeIOS_png, BinaryData::projectIconXcodeIOS_pngSize); + addType (types, MSVCProjectExporterVC2013::getName(), BinaryData::projectIconVisualStudio13_png, BinaryData::projectIconVisualStudio13_pngSize); + addType (types, MSVCProjectExporterVC2012::getName(), BinaryData::projectIconVisualStudio12_png, BinaryData::projectIconVisualStudio12_pngSize); + addType (types, MSVCProjectExporterVC2010::getName(), BinaryData::projectIconVisualStudio10_png, BinaryData::projectIconVisualStudio10_pngSize); + addType (types, MSVCProjectExporterVC2008::getName(), BinaryData::projectIconVisualStudio08_png, BinaryData::projectIconVisualStudio08_pngSize); + addType (types, MSVCProjectExporterVC2005::getName(), BinaryData::projectIconVisualStudio05_png, BinaryData::projectIconVisualStudio05_pngSize); + addType (types, MakefileProjectExporter::getNameLinux(), BinaryData::projectIconLinuxMakefile_png, BinaryData::projectIconLinuxMakefile_pngSize); + addType (types, AndroidProjectExporter::getNameAndroid(), BinaryData::projectIconAndroid_png, BinaryData::projectIconAndroid_pngSize); + addType (types, CodeBlocksProjectExporter::getNameCodeBlocks(), BinaryData::projectIconCodeblocks_png, BinaryData::projectIconCodeblocks_pngSize); + + return types; +} + +StringArray ProjectExporter::getExporterNames() +{ + StringArray s; + Array types (getExporterTypes()); + + for (int i = 0; i < types.size(); ++i) + s.add (types.getReference(i).name); + + return s; +} + +String ProjectExporter::getCurrentPlatformExporterName() +{ + #if JUCE_MAC + return XCodeProjectExporter::getNameMac(); + #elif JUCE_WINDOWS + return MSVCProjectExporterVC2010::getName(); + #elif JUCE_LINUX + return MakefileProjectExporter::getNameLinux(); + #else + #error // huh? + #endif +} + +ProjectExporter* ProjectExporter::createNewExporter (Project& project, const int index) +{ + ProjectExporter* exp = nullptr; + + switch (index) + { + case 0: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter ::getValueTreeTypeName (false)), false); break; + case 1: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter ::getValueTreeTypeName (true)), true); break; + case 2: exp = new MSVCProjectExporterVC2013 (project, ValueTree (MSVCProjectExporterVC2013::getValueTreeTypeName())); break; + case 3: exp = new MSVCProjectExporterVC2012 (project, ValueTree (MSVCProjectExporterVC2012::getValueTreeTypeName())); break; + case 4: exp = new MSVCProjectExporterVC2010 (project, ValueTree (MSVCProjectExporterVC2010::getValueTreeTypeName())); break; + case 5: exp = new MSVCProjectExporterVC2012 (project, ValueTree (MSVCProjectExporterVC2012::getValueTreeTypeName())); break; + case 6: exp = new MSVCProjectExporterVC2013 (project, ValueTree (MSVCProjectExporterVC2013::getValueTreeTypeName())); break; + case 7: exp = new MSVCProjectExporterVC2015 (project, ValueTree (MSVCProjectExporterVC2015::getValueTreeTypeName())); break; + case 8: exp = new MakefileProjectExporter (project, ValueTree (MakefileProjectExporter ::getValueTreeTypeName())); break; + case 9: exp = new AndroidProjectExporter (project, ValueTree (AndroidProjectExporter ::getValueTreeTypeName())); break; + case 10: exp = new CodeBlocksProjectExporter (project, ValueTree (CodeBlocksProjectExporter::getValueTreeTypeName())); break; + + default: jassertfalse; return 0; + } + + exp->createDefaultConfigs(); + exp->createDefaultModulePaths(); + + return exp; +} + +ProjectExporter* ProjectExporter::createNewExporter (Project& project, const String& name) +{ + return createNewExporter (project, getExporterNames().indexOf (name)); +} + +ProjectExporter* ProjectExporter::createExporter (Project& project, const ValueTree& settings) +{ + ProjectExporter* exp = MSVCProjectExporterVC2005::createForSettings (project, settings); + if (exp == nullptr) exp = MSVCProjectExporterVC2008::createForSettings (project, settings); + if (exp == nullptr) exp = MSVCProjectExporterVC2010::createForSettings (project, settings); + if (exp == nullptr) exp = MSVCProjectExporterVC2012::createForSettings (project, settings); + if (exp == nullptr) exp = MSVCProjectExporterVC2013::createForSettings (project, settings); + if (exp == nullptr) exp = MSVCProjectExporterVC2015::createForSettings (project, settings); + if (exp == nullptr) exp = XCodeProjectExporter ::createForSettings (project, settings); + if (exp == nullptr) exp = MakefileProjectExporter ::createForSettings (project, settings); + if (exp == nullptr) exp = AndroidProjectExporter ::createForSettings (project, settings); + if (exp == nullptr) exp = CodeBlocksProjectExporter::createForSettings (project, settings); + + jassert (exp != nullptr); + return exp; +} + +bool ProjectExporter::canProjectBeLaunched (Project* project) +{ + if (project != nullptr) + { + const char* types[] = + { + #if JUCE_MAC + XCodeProjectExporter::getValueTreeTypeName (false), + XCodeProjectExporter::getValueTreeTypeName (true), + #elif JUCE_WINDOWS + MSVCProjectExporterVC2005::getValueTreeTypeName(), + MSVCProjectExporterVC2008::getValueTreeTypeName(), + MSVCProjectExporterVC2010::getValueTreeTypeName(), + MSVCProjectExporterVC2012::getValueTreeTypeName(), + MSVCProjectExporterVC2013::getValueTreeTypeName(), + MSVCProjectExporterVC2015::getValueTreeTypeName(), + #elif JUCE_LINUX + // (this doesn't currently launch.. not really sure what it would do on linux) + //MakefileProjectExporter::getValueTreeTypeName(), + #endif + + nullptr + }; + + for (const char** type = types; *type != nullptr; ++type) + if (project->getExporters().getChildWithName (*type).isValid()) + return true; + } + + return false; +} + +//============================================================================== +ProjectExporter::ProjectExporter (Project& p, const ValueTree& state) + : xcodeIsBundle (false), + xcodeCreatePList (false), + xcodeCanUseDwarf (true), + makefileIsDLL (false), + msvcIsDLL (false), + msvcIsWindowsSubsystem (true), + settings (state), + project (p), + projectType (p.getProjectType()), + projectName (p.getTitle()), + projectFolder (p.getProjectFolder()), + modulesGroup (nullptr) +{ +} + +ProjectExporter::~ProjectExporter() +{ +} + +File ProjectExporter::getTargetFolder() const +{ + return project.resolveFilename (getTargetLocationString()); +} + +RelativePath ProjectExporter::rebaseFromProjectFolderToBuildTarget (const RelativePath& path) const +{ + return path.rebased (project.getProjectFolder(), getTargetFolder(), RelativePath::buildTargetFolder); +} + +bool ProjectExporter::shouldFileBeCompiledByDefault (const RelativePath& file) const +{ + return file.hasFileExtension (cOrCppFileExtensions) + || file.hasFileExtension (asmFileExtensions); +} + +void ProjectExporter::createPropertyEditors (PropertyListBuilder& props) +{ + props.add (new TextPropertyComponent (getTargetLocationValue(), "Target Project Folder", 2048, false), + "The location of the folder in which the " + name + " project will be created. " + "This path can be absolute, but it's much more sensible to make it relative to the jucer project directory."); + + OwnedArray modules; + project.getModules().createRequiredModules (modules); + + for (int i = 0; i < modules.size(); ++i) + modules.getUnchecked(i)->createPropertyEditors (*this, props); + + props.add (new TextPropertyComponent (getExporterPreprocessorDefs(), "Extra Preprocessor Definitions", 32768, true), + "Extra preprocessor definitions. Use the form \"NAME1=value NAME2=value\", using whitespace, commas, " + "or new-lines to separate the items - to include a space or comma in a definition, precede it with a backslash."); + + props.add (new TextPropertyComponent (getExtraCompilerFlags(), "Extra compiler flags", 8192, true), + "Extra command-line flags to be passed to the compiler. This string can contain references to preprocessor definitions in the " + "form ${NAME_OF_DEFINITION}, which will be replaced with their values."); + + props.add (new TextPropertyComponent (getExtraLinkerFlags(), "Extra linker flags", 8192, true), + "Extra command-line flags to be passed to the linker. You might want to use this for adding additional libraries. " + "This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values."); + + props.add (new TextPropertyComponent (getExternalLibraries(), "External libraries to link", 8192, true), + "Additional libraries to link (one per line). You should not add any platform specific decoration to these names. " + "This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values."); + + { + OwnedArray images; + project.findAllImageItems (images); + + StringArray choices; + Array ids; + + choices.add (""); + ids.add (var::null); + choices.add (String::empty); + ids.add (var::null); + + for (int i = 0; i < images.size(); ++i) + { + choices.add (images.getUnchecked(i)->getName()); + ids.add (images.getUnchecked(i)->getID()); + } + + props.add (new ChoicePropertyComponent (getSmallIconImageItemID(), "Icon (small)", choices, ids), + "Sets an icon to use for the executable."); + + props.add (new ChoicePropertyComponent (getBigIconImageItemID(), "Icon (large)", choices, ids), + "Sets an icon to use for the executable."); + } + + createExporterProperties (props); + + props.add (new TextPropertyComponent (getUserNotes(), "Notes", 32768, true), + "Extra comments: This field is not used for code or project generation, it's just a space where you can express your thoughts."); +} + +StringPairArray ProjectExporter::getAllPreprocessorDefs (const ProjectExporter::BuildConfiguration& config) const +{ + StringPairArray defs (mergePreprocessorDefs (config.getAllPreprocessorDefs(), + parsePreprocessorDefs (getExporterPreprocessorDefsString()))); + addDefaultPreprocessorDefs (defs); + return defs; +} + +StringPairArray ProjectExporter::getAllPreprocessorDefs() const +{ + StringPairArray defs (mergePreprocessorDefs (project.getPreprocessorDefs(), + parsePreprocessorDefs (getExporterPreprocessorDefsString()))); + addDefaultPreprocessorDefs (defs); + return defs; +} + +void ProjectExporter::addDefaultPreprocessorDefs (StringPairArray& defs) const +{ + defs.set (getExporterIdentifierMacro(), "1"); + defs.set ("JUCE_APP_VERSION", project.getVersionString()); + defs.set ("JUCE_APP_VERSION_HEX", project.getVersionAsHex()); +} + +String ProjectExporter::replacePreprocessorTokens (const ProjectExporter::BuildConfiguration& config, const String& sourceString) const +{ + return replacePreprocessorDefs (getAllPreprocessorDefs (config), sourceString); +} + +void ProjectExporter::copyMainGroupFromProject() +{ + jassert (itemGroups.size() == 0); + itemGroups.add (project.getMainGroup().createCopy()); +} + +Project::Item& ProjectExporter::getModulesGroup() +{ + if (modulesGroup == nullptr) + { + jassert (itemGroups.size() > 0); // must call copyMainGroupFromProject before this. + itemGroups.add (Project::Item::createGroup (project, "Juce Modules", "__modulesgroup__")); + modulesGroup = &(itemGroups.getReference (itemGroups.size() - 1)); + } + + return *modulesGroup; +} + +void ProjectExporter::addToExtraSearchPaths (const RelativePath& pathFromProjectFolder) +{ + RelativePath localPath (rebaseFromProjectFolderToBuildTarget (pathFromProjectFolder)); + + const String path (isVisualStudio() ? localPath.toWindowsStyle() : localPath.toUnixStyle()); + extraSearchPaths.addIfNotAlreadyThere (path, false); +} + +Value ProjectExporter::getPathForModuleValue (const String& moduleID) +{ + UndoManager* um = project.getUndoManagerFor (settings); + + ValueTree paths (settings.getOrCreateChildWithName (Ids::MODULEPATHS, um)); + ValueTree m (paths.getChildWithProperty (Ids::ID, moduleID)); + + if (! m.isValid()) + { + m = ValueTree (Ids::MODULEPATH); + m.setProperty (Ids::ID, moduleID, um); + paths.addChild (m, -1, um); + } + + return m.getPropertyAsValue (Ids::path, um); +} + +String ProjectExporter::getPathForModuleString (const String& moduleID) const +{ + return settings.getChildWithName (Ids::MODULEPATHS) + .getChildWithProperty (Ids::ID, moduleID) [Ids::path].toString(); +} + +void ProjectExporter::removePathForModule (const String& moduleID) +{ + ValueTree paths (settings.getChildWithName (Ids::MODULEPATHS)); + ValueTree m (paths.getChildWithProperty (Ids::ID, moduleID)); + paths.removeChild (m, project.getUndoManagerFor (settings)); +} + +RelativePath ProjectExporter::getModuleFolderRelativeToProject (const String& moduleID, ProjectSaver& projectSaver) const +{ + if (project.getModules().shouldCopyModuleFilesLocally (moduleID).getValue()) + return RelativePath (project.getRelativePathForFile (projectSaver.getLocalModuleFolder (moduleID)), + RelativePath::projectFolder); + + String path (getPathForModuleString (moduleID)); + + if (path.isEmpty()) + return getLegacyModulePath (moduleID).getChildFile (moduleID); + + return RelativePath (path, RelativePath::projectFolder).getChildFile (moduleID); +} + +String ProjectExporter::getLegacyModulePath() const +{ + return getSettingString ("juceFolder"); +} + +RelativePath ProjectExporter::getLegacyModulePath (const String& moduleID) const +{ + if (project.getModules().state.getChildWithProperty (Ids::ID, moduleID) ["useLocalCopy"]) + return RelativePath (project.getRelativePathForFile (project.getGeneratedCodeFolder() + .getChildFile ("modules") + .getChildFile (moduleID)), RelativePath::projectFolder); + + String oldJucePath (getLegacyModulePath()); + + if (oldJucePath.isEmpty()) + return RelativePath(); + + RelativePath p (oldJucePath, RelativePath::projectFolder); + if (p.getFileName() != "modules") + p = p.getChildFile ("modules"); + + return p.getChildFile (moduleID); +} + +void ProjectExporter::updateOldModulePaths() +{ + String oldPath (getLegacyModulePath()); + + if (oldPath.isNotEmpty()) + { + for (int i = project.getModules().getNumModules(); --i >= 0;) + { + String modID (project.getModules().getModuleID(i)); + getPathForModuleValue (modID) = getLegacyModulePath (modID).getParentDirectory().toUnixStyle(); + } + + settings.removeProperty ("juceFolder", nullptr); + } +} + +static bool areCompatibleExporters (const ProjectExporter& p1, const ProjectExporter& p2) +{ + return (p1.isVisualStudio() && p2.isVisualStudio()) + || (p1.isXcode() && p2.isXcode()) + || (p1.isLinux() && p2.isLinux()) + || (p1.isAndroid() && p2.isAndroid()) + || (p1.isCodeBlocks() && p2.isCodeBlocks()); +} + +void ProjectExporter::createDefaultModulePaths() +{ + for (Project::ExporterIterator exporter (project); exporter.next();) + { + if (areCompatibleExporters (*this, *exporter)) + { + for (int i = project.getModules().getNumModules(); --i >= 0;) + { + String modID (project.getModules().getModuleID(i)); + getPathForModuleValue (modID) = exporter->getPathForModuleValue (modID).getValue(); + } + + return; + } + } + + for (Project::ExporterIterator exporter (project); exporter.next();) + { + if (exporter->canLaunchProject()) + { + for (int i = project.getModules().getNumModules(); --i >= 0;) + { + String modID (project.getModules().getModuleID(i)); + getPathForModuleValue (modID) = exporter->getPathForModuleValue (modID).getValue(); + } + + return; + } + } + + for (int i = project.getModules().getNumModules(); --i >= 0;) + { + String modID (project.getModules().getModuleID(i)); + getPathForModuleValue (modID) = "../../juce"; + } +} + +//============================================================================== +ValueTree ProjectExporter::getConfigurations() const +{ + return settings.getChildWithName (Ids::CONFIGURATIONS); +} + +int ProjectExporter::getNumConfigurations() const +{ + return getConfigurations().getNumChildren(); +} + +ProjectExporter::BuildConfiguration::Ptr ProjectExporter::getConfiguration (int index) const +{ + return createBuildConfig (getConfigurations().getChild (index)); +} + +bool ProjectExporter::hasConfigurationNamed (const String& nameToFind) const +{ + const ValueTree configs (getConfigurations()); + for (int i = configs.getNumChildren(); --i >= 0;) + if (configs.getChild(i) [Ids::name].toString() == nameToFind) + return true; + + return false; +} + +String ProjectExporter::getUniqueConfigName (String nm) const +{ + String nameRoot (nm); + while (CharacterFunctions::isDigit (nameRoot.getLastCharacter())) + nameRoot = nameRoot.dropLastCharacters (1); + + nameRoot = nameRoot.trim(); + + int suffix = 2; + while (hasConfigurationNamed (name)) + nm = nameRoot + " " + String (suffix++); + + return nm; +} + +void ProjectExporter::addNewConfiguration (const BuildConfiguration* configToCopy) +{ + const String configName (getUniqueConfigName (configToCopy != nullptr ? configToCopy->config [Ids::name].toString() + : "New Build Configuration")); + + ValueTree configs (getConfigurations()); + + if (! configs.isValid()) + { + settings.addChild (ValueTree (Ids::CONFIGURATIONS), 0, project.getUndoManagerFor (settings)); + configs = getConfigurations(); + } + + ValueTree newConfig (Ids::CONFIGURATION); + if (configToCopy != nullptr) + newConfig = configToCopy->config.createCopy(); + + newConfig.setProperty (Ids::name, configName, 0); + + configs.addChild (newConfig, -1, project.getUndoManagerFor (configs)); +} + +void ProjectExporter::BuildConfiguration::removeFromExporter() +{ + ValueTree configs (config.getParent()); + configs.removeChild (config, project.getUndoManagerFor (configs)); +} + +void ProjectExporter::createDefaultConfigs() +{ + settings.getOrCreateChildWithName (Ids::CONFIGURATIONS, nullptr); + + for (int i = 0; i < 2; ++i) + { + addNewConfiguration (nullptr); + BuildConfiguration::Ptr config (getConfiguration (i)); + + const bool debugConfig = i == 0; + + config->getNameValue() = debugConfig ? "Debug" : "Release"; + config->isDebugValue() = debugConfig; + config->getOptimisationLevel() = debugConfig ? optimisationOff : optimiseMinSize; + config->getTargetBinaryName() = project.getProjectFilenameRoot(); + } +} + +Drawable* ProjectExporter::getBigIcon() const +{ + return project.getMainGroup().findItemWithID (settings [Ids::bigIcon]).loadAsImageFile(); +} + +Drawable* ProjectExporter::getSmallIcon() const +{ + return project.getMainGroup().findItemWithID (settings [Ids::smallIcon]).loadAsImageFile(); +} + +Image ProjectExporter::getBestIconForSize (int size, bool returnNullIfNothingBigEnough) const +{ + Drawable* im = nullptr; + + ScopedPointer im1 (getSmallIcon()); + ScopedPointer im2 (getBigIcon()); + + if (im1 != nullptr && im2 != nullptr) + { + if (im1->getWidth() >= size && im2->getWidth() >= size) + im = im1->getWidth() < im2->getWidth() ? im1 : im2; + else if (im1->getWidth() >= size) + im = im1; + else if (im2->getWidth() >= size) + im = im2; + } + else + { + im = im1 != nullptr ? im1 : im2; + } + + if (im == nullptr) + return Image(); + + if (returnNullIfNothingBigEnough && im->getWidth() < size && im->getHeight() < size) + return Image(); + + return rescaleImageForIcon (*im, size); +} + +Image ProjectExporter::rescaleImageForIcon (Drawable& d, const int size) +{ + if (DrawableImage* drawableImage = dynamic_cast (&d)) + { + Image im = SoftwareImageType().convert (drawableImage->getImage()); + + if (size == im.getWidth() && size == im.getHeight()) + return im; + + // (scale it down in stages for better resampling) + while (im.getWidth() > 2 * size && im.getHeight() > 2 * size) + im = im.rescaled (im.getWidth() / 2, + im.getHeight() / 2); + + Image newIm (Image::ARGB, size, size, true, SoftwareImageType()); + Graphics g (newIm); + g.drawImageWithin (im, 0, 0, size, size, + RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false); + return newIm; + } + + Image im (Image::ARGB, size, size, true, SoftwareImageType()); + Graphics g (im); + d.drawWithin (g, im.getBounds().toFloat(), RectanglePlacement::centred, 1.0f); + return im; +} + + +//============================================================================== +ProjectExporter::ConfigIterator::ConfigIterator (ProjectExporter& e) + : index (-1), exporter (e) +{ +} + +bool ProjectExporter::ConfigIterator::next() +{ + if (++index >= exporter.getNumConfigurations()) + return false; + + config = exporter.getConfiguration (index); + return true; +} + +ProjectExporter::ConstConfigIterator::ConstConfigIterator (const ProjectExporter& exporter_) + : index (-1), exporter (exporter_) +{ +} + +bool ProjectExporter::ConstConfigIterator::next() +{ + if (++index >= exporter.getNumConfigurations()) + return false; + + config = exporter.getConfiguration (index); + return true; +} + +//============================================================================== +ProjectExporter::BuildConfiguration::BuildConfiguration (Project& p, const ValueTree& configNode) + : config (configNode), project (p) +{ +} + +ProjectExporter::BuildConfiguration::~BuildConfiguration() +{ +} + +String ProjectExporter::BuildConfiguration::getGCCOptimisationFlag() const +{ + switch (getOptimisationLevelInt()) + { + case optimiseMaxSpeed: return "3"; + case optimiseMinSize: return "s"; + default: return "0"; + } +} + +void ProjectExporter::BuildConfiguration::createPropertyEditors (PropertyListBuilder& props) +{ + props.add (new TextPropertyComponent (getNameValue(), "Name", 96, false), + "The name of this configuration."); + + props.add (new BooleanPropertyComponent (isDebugValue(), "Debug mode", "Debugging enabled"), + "If enabled, this means that the configuration should be built with debug synbols."); + + static const char* optimisationLevels[] = { "No optimisation", "Minimise size", "Maximise speed", 0 }; + const int optimisationLevelValues[] = { optimisationOff, optimiseMinSize, optimiseMaxSpeed, 0 }; + props.add (new ChoicePropertyComponent (getOptimisationLevel(), "Optimisation", + StringArray (optimisationLevels), Array (optimisationLevelValues)), + "The optimisation level for this configuration"); + + props.add (new TextPropertyComponent (getTargetBinaryName(), "Binary name", 256, false), + "The filename to use for the destination binary executable file. If you don't add a suffix to this name, " + "a suitable platform-specific suffix will be added automatically."); + + props.add (new TextPropertyComponent (getTargetBinaryRelativePath(), "Binary location", 1024, false), + "The folder in which the finished binary should be placed. Leave this blank to cause the binary to be placed " + "in its default location in the build folder."); + + props.addSearchPathProperty (getHeaderSearchPathValue(), "Header search paths", "Extra header search paths."); + props.addSearchPathProperty (getLibrarySearchPathValue(), "Extra library search paths", "Extra library search paths."); + + props.add (new TextPropertyComponent (getBuildConfigPreprocessorDefs(), "Preprocessor definitions", 32768, true), + "Extra preprocessor definitions. Use the form \"NAME1=value NAME2=value\", using whitespace, commas, or " + "new-lines to separate the items - to include a space or comma in a definition, precede it with a backslash."); + + createConfigProperties (props); + + props.add (new TextPropertyComponent (getUserNotes(), "Notes", 32768, true), + "Extra comments: This field is not used for code or project generation, it's just a space where you can express your thoughts."); +} + +StringPairArray ProjectExporter::BuildConfiguration::getAllPreprocessorDefs() const +{ + return mergePreprocessorDefs (project.getPreprocessorDefs(), + parsePreprocessorDefs (getBuildConfigPreprocessorDefsString())); +} + +StringArray ProjectExporter::BuildConfiguration::getHeaderSearchPaths() const +{ + return getSearchPathsFromString (getHeaderSearchPathString()); +} + +StringArray ProjectExporter::BuildConfiguration::getLibrarySearchPaths() const +{ + return getSearchPathsFromString (getLibrarySearchPathString()); +} + +String ProjectExporter::BuildConfiguration::getGCCLibraryPathFlags() const +{ + String s; + const StringArray libraryPaths (getLibrarySearchPaths()); + + for (int i = 0; i < libraryPaths.size(); ++i) + s << " -L" << addQuotesIfContainsSpaces (libraryPaths[i]); + + return s; +} + +String ProjectExporter::getExternalLibraryFlags (const BuildConfiguration& config) const +{ + StringArray libraries; + libraries.addTokens (getExternalLibrariesString(), ";\n", "\"'"); + libraries.removeEmptyStrings (true); + + if (libraries.size() != 0) + return replacePreprocessorTokens (config, "-l" + libraries.joinIntoString (" -l")).trim(); + + return String::empty; +}