diff --git a/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h b/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h index 4dee4ce789..67eda31db6 100644 --- a/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h +++ b/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h @@ -75,14 +75,8 @@ public: auto juceValue = getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()); auto userValue = getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()); - auto jucePathNeedsScanning = (! juceValue.isUsingDefault() && juceValue.get() != lastJUCEModulePath); - auto userPathNeedsScanning = (! userValue.isUsingDefault() && userValue.get() != lastUserModulePath); - - if (jucePathNeedsScanning) - ProjucerApplication::getApp().rescanJUCEPathModules(); - - if (userPathNeedsScanning) - ProjucerApplication::getApp().rescanUserPathModules(); + if (juceValue.get() != lastJUCEModulePath) ProjucerApplication::getApp().rescanJUCEPathModules(); + if (userValue.get() != lastUserModulePath) ProjucerApplication::getApp().rescanUserPathModules(); } void paint (Graphics& g) override diff --git a/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp b/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp index d852991a71..fdaa55c44f 100644 --- a/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp +++ b/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp @@ -256,7 +256,7 @@ public: build.setGlobalDefs (getGlobalDefs()); build.setCompileFlags (project.getCompileEngineSettings().getExtraCompilerFlagsString()); build.setExtraDLLs (getExtraDLLs()); - build.setJuceModulesFolder (EnabledModuleList::findDefaultModulesFolder (project).getFullPathName()); + build.setJuceModulesFolder (project.getEnabledModules().getDefaultModulesFolder().getFullPathName()); build.setUtilsCppInclude (project.getAppIncludeFile().getFullPathName()); @@ -388,10 +388,10 @@ private: { for (auto* m : modules) { - auto localModuleFolder = proj.getEnabledModules().shouldCopyModuleFilesLocally (m->moduleInfo.getID()).getValue() - ? proj.getLocalModuleFolder (m->moduleInfo.getID()) - : m->moduleInfo.getFolder(); + auto copyLocally = proj.getEnabledModules().shouldCopyModuleFilesLocally (m->moduleInfo.getID()); + auto localModuleFolder = copyLocally ? proj.getLocalModuleFolder (m->moduleInfo.getID()) + : m->moduleInfo.getFolder(); m->findAndAddCompiledUnits (*exporter, nullptr, compileUnits, isPluginProject || isVSTHost ? ProjectType::Target::SharedCodeTarget diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h index 7917a4fdd4..709a23a243 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h @@ -153,6 +153,7 @@ private: group.properties.clear(); exporterModulePathDefaultValues.clear(); exporterModulePathValues.clear(); + globalPathValues.clear(); for (Project::ExporterIterator exporter (project); exporter.next();) { @@ -179,34 +180,39 @@ private: "This can be an absolute path, or relative to the jucer project folder, but it " "must be valid on the filesystem of the target machine that will be performing this build. If this " "is empty then the global path will be used."); + + globalPathValues.add (getAppSettings().getStoredPath (isJUCEModule (moduleID) ? Ids::defaultJuceModulePath : Ids::defaultUserModulePath, + exporter->getTargetOSForExporter()).getPropertyAsValue()); } for (int i = 0; i < exporterModulePathDefaultValues.size(); ++i) { exporterModulePathDefaultValues.getReference (i).onDefaultChange = [this] { startTimer (50); }; + exporterModulePathValues.getReference (i).addListener (this); + globalPathValues.getReference (i).addListener (this); } - globalPathValue.removeListener (this); - globalPathValue.referTo (modules.getShouldUseGlobalPathValue (moduleID)); - globalPathValue.addListener (this); + useGlobalPathValue.removeListener (this); + useGlobalPathValue.referTo (modules.shouldUseGlobalPathValue (moduleID)); + useGlobalPathValue.addListener (this); auto menuItemString = (TargetOS::getThisOS() == TargetOS::osx ? "\"Projucer->Global Paths...\"" : "\"File->Global Paths...\""); - props.add (new BooleanPropertyComponent (globalPathValue, + props.add (new BooleanPropertyComponent (useGlobalPathValue, "Use global path", "Use global path for this module"), String ("If this is enabled, then the locally-stored global path (set in the ") + menuItemString + " menu item) " "will be used as the path to this module. " "This means that if this Projucer project is opened on another machine it will use that machine's global path as the path to this module."); - props.add (new BooleanPropertyComponent (modules.shouldCopyModuleFilesLocally (moduleID), + props.add (new BooleanPropertyComponent (modules.shouldCopyModuleFilesLocallyValue (moduleID), "Create local copy", "Copy the module into the project folder"), "If this is enabled, then a local copy of the entire module will be made inside your project (in the auto-generated JuceLibraryFiles folder), " "so that your project will be self-contained, and won't need to contain any references to files in other folders. " "This also means that you can check the module into your source-control system to make sure it is always in sync with your own code."); - props.add (new BooleanPropertyComponent (modules.shouldShowAllModuleFilesInProject (moduleID), + props.add (new BooleanPropertyComponent (modules.shouldShowAllModuleFilesInProjectValue (moduleID), "Add source to project", "Make module files browsable in projects"), "If this is enabled, then the entire source tree from this module will be shown inside your project, " "making it easy to browse/edit the module's classes. If disabled, then only the minimum number of files " @@ -262,8 +268,8 @@ private: //============================================================================== Array exporterModulePathDefaultValues; - Array exporterModulePathValues; - Value globalPathValue; + Array exporterModulePathValues, globalPathValues; + Value useGlobalPathValue; OwnedArray configFlags; @@ -475,7 +481,7 @@ class EnabledModulesItem : public ProjectTreeItemBase, public: EnabledModulesItem (Project& p) : project (p), - moduleListTree (p.getEnabledModules().state) + moduleListTree (project.getEnabledModules().getState()) { moduleListTree.addListener (this); @@ -618,7 +624,7 @@ public: } else if (resultCode > 0) { - std::vector list; + std::vector list; int offset = -1; if (resultCode < 200) diff --git a/extras/Projucer/Source/Project/UI/jucer_ModulesInformationComponent.h b/extras/Projucer/Source/Project/UI/jucer_ModulesInformationComponent.h index 0b2ef9f60a..d78f9c02b5 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ModulesInformationComponent.h +++ b/extras/Projucer/Source/Project/UI/jucer_ModulesInformationComponent.h @@ -35,7 +35,7 @@ class ModulesInformationComponent : public Component, public: ModulesInformationComponent (Project& p) : project (p), - modulesValueTree (p.getEnabledModules().state) + modulesValueTree (project.getEnabledModules().getState()) { listHeader = new ListBoxHeader ( { "Module", "Version", "Make Local Copy", "Paths" }, { 0.25f, 0.2f, 0.2f, 0.35f } ); @@ -135,9 +135,8 @@ public: g.drawFittedText (version, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (1) * width)), Justification::centredLeft, 1); //============================================================================== - auto copyLocally = project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID).getValue() ? "Yes" : "No"; - - g.drawFittedText (copyLocally, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * width)), Justification::centredLeft, 1); + g.drawFittedText (String (project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID) ? "Yes" : "No"), + bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * width)), Justification::centredLeft, 1); //============================================================================== String pathText; @@ -215,33 +214,41 @@ private: repaint(); } + static void setLocalCopyModeForAllModules (Project& project, bool copyLocally) + { + auto& modules = project.getEnabledModules(); + + for (auto i = modules.getNumModules(); --i >= 0;) + modules.shouldCopyModuleFilesLocallyValue (modules.getModuleID (i)) = copyLocally; + } + void showCopyModeMenu() { PopupMenu m; m.addItem (PopupMenu::Item ("Set all modules to copy locally") - .setAction ([&] { project.getEnabledModules().setLocalCopyModeForAllModules (true); })); + .setAction ([&] { setLocalCopyModeForAllModules (project, true); })); m.addItem (PopupMenu::Item ("Set all modules to not copy locally") - .setAction ([&] { project.getEnabledModules().setLocalCopyModeForAllModules (false); })); + .setAction ([&] { setLocalCopyModeForAllModules (project, false); })); m.showMenuAsync (PopupMenu::Options().withTargetComponent (setCopyModeButton)); } static void setAllModulesToUseGlobalPaths (Project& project, bool useGlobal) { - auto& moduleList = project.getEnabledModules(); + auto& modules = project.getEnabledModules(); - for (auto id : moduleList.getAllModules()) - moduleList.getShouldUseGlobalPathValue (id).setValue (useGlobal); + for (auto moduleID : modules.getAllModules()) + modules.shouldUseGlobalPathValue (moduleID) = useGlobal; } static void setSelectedModulesToUseGlobalPaths (Project& project, SparseSet selected, bool useGlobal) { - auto& moduleList = project.getEnabledModules(); + auto& modules = project.getEnabledModules(); for (int i = 0; i < selected.size(); ++i) - moduleList.getShouldUseGlobalPathValue (moduleList.getModuleID (selected[i])).setValue (useGlobal); + modules.shouldUseGlobalPathValue (modules.getModuleID (selected[i])) = useGlobal; } void showGlobalPathsMenu() diff --git a/extras/Projucer/Source/Project/jucer_Module.cpp b/extras/Projucer/Source/Project/jucer_Module.cpp index a81d322ce3..f5ea011bbe 100644 --- a/extras/Projucer/Source/Project/jucer_Module.cpp +++ b/extras/Projucer/Source/Project/jucer_Module.cpp @@ -40,7 +40,7 @@ File ModuleDescription::getHeader() const { if (moduleFolder != File()) { - const char* extensions[] = { ".h", ".hpp", ".hxx" }; + static const char* extensions[] = { ".h", ".hpp", ".hxx" }; for (auto e : extensions) { @@ -56,14 +56,15 @@ File ModuleDescription::getHeader() const StringArray ModuleDescription::getDependencies() const { - auto deps = StringArray::fromTokens (moduleInfo ["dependencies"].toString(), " \t;,", "\"'"); - deps.trim(); - deps.removeEmptyStrings(); - return deps; + auto moduleDependencies = StringArray::fromTokens (moduleInfo ["dependencies"].toString(), " \t;,", "\"'"); + moduleDependencies.trim(); + moduleDependencies.removeEmptyStrings(); + + return moduleDependencies; } //============================================================================== -static bool tryToAddModuleFromFolder (const File& path, ModuleIDAndFolderList& list) +static bool tryToAddModuleFromFolder (const File& path, AvailableModuleList::ModuleIDAndFolderList& list) { ModuleDescription m (path); @@ -76,7 +77,7 @@ static bool tryToAddModuleFromFolder (const File& path, ModuleIDAndFolderList& l return false; } -static void addAllModulesInSubfoldersRecursively (const File& path, int depth, ModuleIDAndFolderList& list) +static void addAllModulesInSubfoldersRecursively (const File& path, int depth, AvailableModuleList::ModuleIDAndFolderList& list) { if (depth > 0) { @@ -94,27 +95,19 @@ static void addAllModulesInSubfoldersRecursively (const File& path, int depth, M } } -static void addAllModulesInFolder (const File& path, ModuleIDAndFolderList& list) +static void addAllModulesInFolder (const File& path, AvailableModuleList::ModuleIDAndFolderList& list) { if (! tryToAddModuleFromFolder (path, list)) { - int subfolders = 3; + static constexpr int subfolders = 3; addAllModulesInSubfoldersRecursively (path, subfolders, list); } } -static void sort (ModuleIDAndFolderList& listToSort) -{ - std::sort (listToSort.begin(), listToSort.end(), [] (const ModuleIDAndFolder& m1, const ModuleIDAndFolder& m2) - { - return m1.first.compareIgnoreCase (m2.first) < 0; - }); -} - -//============================================================================== -struct ModuleScannerJob : public ThreadPoolJob +struct ModuleScannerJob : public ThreadPoolJob { - ModuleScannerJob (const Array& paths, std::function&& callback) + ModuleScannerJob (const Array& paths, + std::function&& callback) : ThreadPoolJob ("ModuleScannerJob"), pathsToScan (paths), completionCallback (std::move (callback)) @@ -123,14 +116,19 @@ struct ModuleScannerJob : public ThreadPoolJob JobStatus runJob() override { - ModuleIDAndFolderList list; + AvailableModuleList::ModuleIDAndFolderList list; for (auto& p : pathsToScan) addAllModulesInFolder (p, list); if (! shouldExit()) { - sort (list); + std::sort (list.begin(), list.end(), [] (const AvailableModuleList::ModuleIDAndFolder& m1, + const AvailableModuleList::ModuleIDAndFolder& m2) + { + return m1.first.compareIgnoreCase (m2.first) < 0; + }); + completionCallback (list); } @@ -138,16 +136,12 @@ struct ModuleScannerJob : public ThreadPoolJob } Array pathsToScan; - std::function completionCallback; + std::function completionCallback; }; -AvailableModuleList::AvailableModuleList() -{ -} - ThreadPoolJob* AvailableModuleList::createScannerJob (const Array& paths) { - return new ModuleScannerJob (paths, [this] (ModuleIDAndFolderList scannedModuleList) + return new ModuleScannerJob (paths, [this] (AvailableModuleList::ModuleIDAndFolderList scannedModuleList) { { const ScopedLock swapLock (lock); @@ -177,14 +171,13 @@ void AvailableModuleList::scanPathsAsync (const Array& paths) removePendingAndAddJob (createScannerJob (paths)); } -ModuleIDAndFolderList AvailableModuleList::getAllModules() const +AvailableModuleList::ModuleIDAndFolderList AvailableModuleList::getAllModules() const { const ScopedLock readLock (lock); - return moduleList; } -ModuleIDAndFolder AvailableModuleList::getModuleWithID (const String& id) const +AvailableModuleList::ModuleIDAndFolder AvailableModuleList::getModuleWithID (const String& id) const { const ScopedLock readLock (lock); @@ -214,19 +207,18 @@ LibraryModule::LibraryModule (const ModuleDescription& d) { } -//============================================================================== void LibraryModule::writeIncludes (ProjectSaver& projectSaver, OutputStream& out) { auto& project = projectSaver.project; auto& modules = project.getEnabledModules(); - auto id = getID(); + auto moduleID = getID(); - if (modules.shouldCopyModuleFilesLocally (id).getValue()) + if (modules.shouldCopyModuleFilesLocally (moduleID)) { auto juceModuleFolder = moduleInfo.getFolder(); - auto localModuleFolder = project.getLocalModuleFolder (id); + auto localModuleFolder = project.getLocalModuleFolder (moduleID); localModuleFolder.createDirectory(); projectSaver.copyFolder (juceModuleFolder, localModuleFolder); } @@ -236,23 +228,14 @@ void LibraryModule::writeIncludes (ProjectSaver& projectSaver, OutputStream& out << ">" << newLine; } -//============================================================================== -static void parseAndAddLibs (StringArray& libList, const String& libs) -{ - libList.addTokens (libs, ", ", {}); - libList.trim(); - libList.removeDuplicates (false); -} - -void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, ProjectSaver& projectSaver) const +void LibraryModule::addSearchPathsToExporter (ProjectExporter& exporter) const { - auto& project = exporter.getProject(); - auto moduleRelativePath = exporter.getModuleFolderRelativeToProject (getID()); exporter.addToExtraSearchPaths (moduleRelativePath.getParentDirectory()); String libDirPlatform; + if (exporter.isLinux()) libDirPlatform = "Linux"; else if (exporter.isCodeBlocks() && exporter.isWindows()) @@ -261,7 +244,7 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P libDirPlatform = exporter.getTargetFolder().getFileName(); auto libSubdirPath = moduleRelativePath.toUnixStyle() + "/libs/" + libDirPlatform; - auto moduleLibDir = File (project.getProjectFolder().getFullPathName() + "/" + libSubdirPath); + auto moduleLibDir = File (exporter.getProject().getProjectFolder().getFullPathName() + "/" + libSubdirPath); if (moduleLibDir.exists()) exporter.addToModuleLibPaths ({ libSubdirPath, moduleRelativePath.getRoot() }); @@ -275,27 +258,43 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P for (auto& path : paths) exporter.addToExtraSearchPaths (moduleRelativePath.getChildFile (path.unquoted())); } +} - { - auto extraDefs = moduleInfo.getPreprocessorDefs().trim(); +void LibraryModule::addDefinesToExporter (ProjectExporter& exporter) const +{ + auto extraDefs = moduleInfo.getPreprocessorDefs().trim(); - if (extraDefs.isNotEmpty()) - exporter.getExporterPreprocessorDefsValue() = exporter.getExporterPreprocessorDefsString() + "\n" + extraDefs; - } + if (extraDefs.isNotEmpty()) + exporter.getExporterPreprocessorDefsValue() = exporter.getExporterPreprocessorDefsString() + "\n" + extraDefs; +} - { - Array compiled; - auto& modules = project.getEnabledModules(); - auto id = getID(); +void LibraryModule::addCompileUnitsToExporter (ProjectExporter& exporter, ProjectSaver& projectSaver) const +{ + auto& project = exporter.getProject(); + auto& modules = project.getEnabledModules(); - auto localModuleFolder = modules.shouldCopyModuleFilesLocally (id).getValue() ? project.getLocalModuleFolder (id) - : moduleInfo.getFolder(); + auto moduleID = getID(); - findAndAddCompiledUnits (exporter, &projectSaver, compiled); + auto localModuleFolder = modules.shouldCopyModuleFilesLocally (moduleID) ? project.getLocalModuleFolder (moduleID) + : moduleInfo.getFolder(); - if (modules.shouldShowAllModuleFilesInProject (id).getValue()) - addBrowseableCode (exporter, compiled, localModuleFolder); - } + Array compiled; + findAndAddCompiledUnits (exporter, &projectSaver, compiled); + + if (modules.shouldShowAllModuleFilesInProject (moduleID)) + addBrowseableCode (exporter, compiled, localModuleFolder); +} + +void LibraryModule::addLibsToExporter (ProjectExporter& exporter) const +{ + auto parseAndAddLibsToList = [] (StringArray& libList, const String& libs) + { + libList.addTokens (libs, ", ", {}); + libList.trim(); + libList.removeDuplicates (false); + }; + + auto& project = exporter.getProject(); if (exporter.isXcode()) { @@ -312,26 +311,34 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P auto frameworks = moduleInfo.moduleInfo [xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString(); xcodeExporter.xcodeFrameworks.addTokens (frameworks, ", ", {}); - parseAndAddLibs (xcodeExporter.xcodeLibs, moduleInfo.moduleInfo [exporter.isOSX() ? "OSXLibs" : "iOSLibs"].toString()); + parseAndAddLibsToList (xcodeExporter.xcodeLibs, moduleInfo.moduleInfo [exporter.isOSX() ? "OSXLibs" : "iOSLibs"].toString()); } else if (exporter.isLinux()) { - parseAndAddLibs (exporter.linuxLibs, moduleInfo.moduleInfo ["linuxLibs"].toString()); - parseAndAddLibs (exporter.linuxPackages, moduleInfo.moduleInfo ["linuxPackages"].toString()); + parseAndAddLibsToList (exporter.linuxLibs, moduleInfo.moduleInfo ["linuxLibs"].toString()); + parseAndAddLibsToList (exporter.linuxPackages, moduleInfo.moduleInfo ["linuxPackages"].toString()); } else if (exporter.isWindows()) { if (exporter.isCodeBlocks()) - parseAndAddLibs (exporter.mingwLibs, moduleInfo.moduleInfo ["mingwLibs"].toString()); + parseAndAddLibsToList (exporter.mingwLibs, moduleInfo.moduleInfo ["mingwLibs"].toString()); else - parseAndAddLibs (exporter.windowsLibs, moduleInfo.moduleInfo ["windowsLibs"].toString()); + parseAndAddLibsToList (exporter.windowsLibs, moduleInfo.moduleInfo ["windowsLibs"].toString()); } else if (exporter.isAndroid()) { - parseAndAddLibs (exporter.androidLibs, moduleInfo.moduleInfo ["androidLibs"].toString()); + parseAndAddLibsToList (exporter.androidLibs, moduleInfo.moduleInfo ["androidLibs"].toString()); } } +void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, ProjectSaver& projectSaver) const +{ + addSearchPathsToExporter (exporter); + addDefinesToExporter (exporter); + addCompileUnitsToExporter (exporter, projectSaver); + addLibsToExporter (exporter); +} + void LibraryModule::getConfigFlags (Project& project, OwnedArray& flags) const { auto header = moduleInfo.getHeader(); @@ -384,7 +391,25 @@ void LibraryModule::getConfigFlags (Project& project, OwnedArray= 0) + { + auto topLevelGroup = path.substring (0, slash); + auto remainingPath = path.substring (slash + 1); + + auto newGroup = group.getOrCreateSubGroup (topLevelGroup); + addFileWithGroups (newGroup, file, remainingPath); + } + else + { + if (! group.containsChildForFile (file)) + group.addRelativeFile (file, -1, false); + } +} + struct FileSorter { static int compareElements (const File& f1, const File& f2) @@ -393,16 +418,19 @@ struct FileSorter } }; -bool LibraryModule::CompileUnit::hasSuffix (const File& f, const char* suffix) +void LibraryModule::findBrowseableFiles (const File& folder, Array& filesFound) const { - auto fileWithoutSuffix = f.getFileNameWithoutExtension() + "."; + Array tempList; + FileSorter sorter; - return fileWithoutSuffix.containsIgnoreCase (suffix + String (".")) - || fileWithoutSuffix.containsIgnoreCase (suffix + String ("_")); -} + DirectoryIterator iter (folder, true, "*", File::findFiles); + bool isHiddenFile; -void LibraryModule::CompileUnit::writeInclude (MemoryOutputStream&) const -{ + while (iter.next (nullptr, &isHiddenFile, nullptr, nullptr, nullptr, nullptr)) + if (! isHiddenFile && iter.getFile().hasFileExtension (browseableFileExtensions)) + tempList.addSorted (sorter, iter.getFile()); + + filesFound.addArray (tempList); } bool LibraryModule::CompileUnit::isNeededForExporter (ProjectExporter& exporter) const @@ -428,6 +456,14 @@ String LibraryModule::CompileUnit::getFilenameForProxyFile() const return "include_" + file.getFileName(); } +bool LibraryModule::CompileUnit::hasSuffix (const File& f, const char* suffix) +{ + auto fileWithoutSuffix = f.getFileNameWithoutExtension() + "."; + + return fileWithoutSuffix.containsIgnoreCase (suffix + String (".")) + || fileWithoutSuffix.containsIgnoreCase (suffix + String ("_")); +} + Array LibraryModule::getAllCompileUnits (ProjectType::Target::Type forTarget) const { auto files = getFolder().findChildFiles (File::findFiles, false); @@ -486,40 +522,6 @@ void LibraryModule::findAndAddCompiledUnits (ProjectExporter& exporter, } } -static void addFileWithGroups (Project::Item& group, const RelativePath& file, const String& path) -{ - auto slash = path.indexOfChar (File::getSeparatorChar()); - - if (slash >= 0) - { - auto topLevelGroup = path.substring (0, slash); - auto remainingPath = path.substring (slash + 1); - - auto newGroup = group.getOrCreateSubGroup (topLevelGroup); - addFileWithGroups (newGroup, file, remainingPath); - } - else - { - if (! group.containsChildForFile (file)) - group.addRelativeFile (file, -1, false); - } -} - -void LibraryModule::findBrowseableFiles (const File& folder, Array& filesFound) const -{ - Array tempList; - FileSorter sorter; - - DirectoryIterator iter (folder, true, "*", File::findFiles); - bool isHiddenFile; - - while (iter.next (nullptr, &isHiddenFile, nullptr, nullptr, nullptr, nullptr)) - if (! isHiddenFile && iter.getFile().hasFileExtension (browseableFileExtensions)) - tempList.addSorted (sorter, iter.getFile()); - - filesFound.addArray (tempList); -} - void LibraryModule::addBrowseableCode (ProjectExporter& exporter, const Array& compiled, const File& localModuleFolder) const { if (sourceFiles.isEmpty()) @@ -531,7 +533,7 @@ void LibraryModule::addBrowseableCode (ProjectExporter& exporter, const Array (state.getChildWithProperty (Ids::ID, moduleID) - .getProperty (Ids::useGlobalPath)); -} + for (int i = 0; i < getNumModules(); ++i) + moduleIDs.add (getModuleID (i)); -Value EnabledModuleList::getShouldUseGlobalPathValue (const String& moduleID) const -{ - return state.getChildWithProperty (Ids::ID, moduleID) - .getPropertyAsValue (Ids::useGlobalPath, getUndoManager()); + return moduleIDs; } -Value EnabledModuleList::shouldShowAllModuleFilesInProject (const String& moduleID) +void EnabledModuleList::createRequiredModules (OwnedArray& modules) { - return state.getChildWithProperty (Ids::ID, moduleID) - .getPropertyAsValue (Ids::showAllCode, getUndoManager()); + for (int i = 0; i < getNumModules(); ++i) + modules.add (new LibraryModule (getModuleInfo (getModuleID (i)))); } -struct ModuleTreeSorter +void EnabledModuleList::sortAlphabetically() { - static int compareElements (const ValueTree& m1, const ValueTree& m2) + struct ModuleTreeSorter { - return m1[Ids::ID].toString().compareIgnoreCase (m2[Ids::ID]); - } -}; + static int compareElements (const ValueTree& m1, const ValueTree& m2) + { + return m1[Ids::ID].toString().compareIgnoreCase (m2[Ids::ID]); + } + }; -void EnabledModuleList::sortAlphabetically() -{ ModuleTreeSorter sorter; state.sort (sorter, getUndoManager(), false); } -Value EnabledModuleList::shouldCopyModuleFilesLocally (const String& moduleID) const +File EnabledModuleList::getDefaultModulesFolder() const { - return state.getChildWithProperty (Ids::ID, moduleID) - .getPropertyAsValue (Ids::useLocalCopy, getUndoManager()); -} + File globalPath (getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get().toString()); -void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, bool useGlobalPath, bool sendAnalyticsEvent) -{ - ModuleDescription info (moduleFolder); + if (globalPath.exists()) + return globalPath; - if (info.isValid()) + for (auto& exporterPathModule : project.getExporterPathsModuleList().getAllModules()) { - auto moduleID = info.getID(); - - if (! isModuleEnabled (moduleID)) - { - ValueTree module (Ids::MODULE); - module.setProperty (Ids::ID, moduleID, getUndoManager()); - - state.appendChild (module, getUndoManager()); - sortAlphabetically(); - - shouldShowAllModuleFilesInProject (moduleID) = true; - shouldCopyModuleFilesLocally (moduleID) = copyLocally; - getShouldUseGlobalPathValue (moduleID) = useGlobalPath; - - RelativePath path (moduleFolder.getParentDirectory(), - project.getProjectFolder(), RelativePath::projectFolder); - - for (Project::ExporterIterator exporter (project); exporter.next();) - exporter->getPathForModuleValue (moduleID) = path.toUnixStyle(); - - if (! useGlobalPath) - project.rescanExporterPathModules (false); - - if (sendAnalyticsEvent) - { - StringPairArray data; - data.set ("label", moduleID); + auto f = exporterPathModule.second; - Analytics::getInstance()->logEvent ("Module Added", data, ProjucerAnalyticsEvent::projectEvent); - } - } + if (f.isDirectory()) + return f.getParentDirectory(); } -} - -void EnabledModuleList::removeModule (String moduleID) // must be pass-by-value, and not a const ref! -{ - for (auto i = state.getNumChildren(); --i >= 0;) - if (state.getChild(i) [Ids::ID] == moduleID) - state.removeChild (i, getUndoManager()); - for (Project::ExporterIterator exporter (project); exporter.next();) - exporter->removePathForModule (moduleID); + return File::getCurrentWorkingDirectory(); } -void EnabledModuleList::createRequiredModules (OwnedArray& modules) +ModuleDescription EnabledModuleList::getModuleInfo (const String& moduleID) { - for (int i = 0; i < getNumModules(); ++i) - modules.add (new LibraryModule (getModuleInfo (getModuleID (i)))); + return ModuleDescription (project.getModuleWithID (moduleID).second); } -StringArray EnabledModuleList::getAllModules() const +bool EnabledModuleList::isModuleEnabled (const String& moduleID) const { - StringArray moduleIDs; - - for (int i = 0; i < getNumModules(); ++i) - moduleIDs.add (getModuleID (i)); - - return moduleIDs; + return state.getChildWithProperty (Ids::ID, moduleID).isValid(); } static void getDependencies (Project& project, const String& moduleID, StringArray& dependencies) @@ -717,6 +656,39 @@ bool EnabledModuleList::doesModuleHaveHigherCppStandardThanProject (const String return (moduleCppStandard.getIntValue() > projectCppStandard.getIntValue()); } +bool EnabledModuleList::shouldUseGlobalPath (const String& moduleID) const +{ + return (bool) shouldUseGlobalPathValue (moduleID).getValue(); +} + +Value EnabledModuleList::shouldUseGlobalPathValue (const String& moduleID) const +{ + return state.getChildWithProperty (Ids::ID, moduleID) + .getPropertyAsValue (Ids::useGlobalPath, getUndoManager()); +} + +bool EnabledModuleList::shouldShowAllModuleFilesInProject (const String& moduleID) const +{ + return (bool) shouldShowAllModuleFilesInProjectValue (moduleID).getValue(); +} + +Value EnabledModuleList::shouldShowAllModuleFilesInProjectValue (const String& moduleID) const +{ + return state.getChildWithProperty (Ids::ID, moduleID) + .getPropertyAsValue (Ids::showAllCode, getUndoManager()); +} + +bool EnabledModuleList::shouldCopyModuleFilesLocally (const String& moduleID) const +{ + return (bool) shouldCopyModuleFilesLocallyValue (moduleID).getValue(); +} + +Value EnabledModuleList::shouldCopyModuleFilesLocallyValue (const String& moduleID) const +{ + return state.getChildWithProperty (Ids::ID, moduleID) + .getPropertyAsValue (Ids::useLocalCopy, getUndoManager()); +} + bool EnabledModuleList::areMostModulesUsingGlobalPath() const { int numYes = 0, numNo = 0; @@ -738,7 +710,7 @@ bool EnabledModuleList::areMostModulesCopiedLocally() const for (auto i = getNumModules(); --i >= 0;) { - if (shouldCopyModuleFilesLocally (getModuleID (i)).getValue()) + if (shouldCopyModuleFilesLocally (getModuleID (i))) ++numYes; else ++numNo; @@ -747,40 +719,43 @@ bool EnabledModuleList::areMostModulesCopiedLocally() const return numYes > numNo; } -void EnabledModuleList::setLocalCopyModeForAllModules (bool copyLocally) +void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, bool useGlobalPath, bool sendAnalyticsEvent) { - for (auto i = getNumModules(); --i >= 0;) - shouldCopyModuleFilesLocally (project.getEnabledModules().getModuleID (i)) = copyLocally; -} + ModuleDescription info (moduleFolder); -File EnabledModuleList::findDefaultModulesFolder (Project& project) -{ - File globalPath (getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get().toString()); + if (info.isValid()) + { + auto moduleID = info.getID(); - if (globalPath.exists()) - return globalPath; + if (! isModuleEnabled (moduleID)) + { + ValueTree module (Ids::MODULE); + module.setProperty (Ids::ID, moduleID, getUndoManager()); - for (auto& exporterPathModule : project.getExporterPathsModuleList().getAllModules()) - { - auto f = exporterPathModule.second; + state.appendChild (module, getUndoManager()); + sortAlphabetically(); - if (f.isDirectory()) - return f.getParentDirectory(); - } + shouldShowAllModuleFilesInProjectValue (moduleID) = true; + shouldCopyModuleFilesLocallyValue (moduleID) = copyLocally; + shouldUseGlobalPathValue (moduleID) = useGlobalPath; - return File::getCurrentWorkingDirectory(); -} + RelativePath path (moduleFolder.getParentDirectory(), + project.getProjectFolder(), RelativePath::projectFolder); -void EnabledModuleList::addModuleFromUserSelectedFile() -{ - static auto lastLocation = findDefaultModulesFolder (project); + for (Project::ExporterIterator exporter (project); exporter.next();) + exporter->getPathForModuleValue (moduleID) = path.toUnixStyle(); - FileChooser fc ("Select a module to add...", lastLocation, {}); + if (! useGlobalPath) + project.rescanExporterPathModules (false); - if (fc.browseForDirectory()) - { - lastLocation = fc.getResult(); - addModuleOfferingToCopy (lastLocation, true); + if (sendAnalyticsEvent) + { + StringPairArray data; + data.set ("label", moduleID); + + Analytics::getInstance()->logEvent ("Module Added", data, ProjucerAnalyticsEvent::projectEvent); + } + } } } @@ -797,6 +772,19 @@ void EnabledModuleList::addModuleInteractive (const String& moduleID) addModuleFromUserSelectedFile(); } +void EnabledModuleList::addModuleFromUserSelectedFile() +{ + auto lastLocation = getDefaultModulesFolder(); + + FileChooser fc ("Select a module to add...", lastLocation, {}); + + if (fc.browseForDirectory()) + { + lastLocation = fc.getResult(); + addModuleOfferingToCopy (lastLocation, true); + } +} + void EnabledModuleList::addModuleOfferingToCopy (const File& f, bool isFromUserSpecifiedFolder) { ModuleDescription m (f); @@ -820,12 +808,12 @@ void EnabledModuleList::addModuleOfferingToCopy (const File& f, bool isFromUserS true); } -bool isJUCEFolder (const File& f) +void EnabledModuleList::removeModule (String moduleID) // must be pass-by-value, and not a const ref! { - return isJUCEModulesFolder (f.getChildFile ("modules")); -} + for (auto i = state.getNumChildren(); --i >= 0;) + if (state.getChild(i) [Ids::ID] == moduleID) + state.removeChild (i, getUndoManager()); -bool isJUCEModulesFolder (const File& f) -{ - return f.isDirectory() && f.getChildFile ("juce_core").isDirectory(); + for (Project::ExporterIterator exporter (project); exporter.next();) + exporter->removePathForModule (moduleID); } diff --git a/extras/Projucer/Source/Project/jucer_Module.h b/extras/Projucer/Source/Project/jucer_Module.h index ba216b335a..66b986f065 100644 --- a/extras/Projucer/Source/Project/jucer_Module.h +++ b/extras/Projucer/Source/Project/jucer_Module.h @@ -30,16 +30,11 @@ class ProjectExporter; class ProjectSaver; -//============================================================================== -bool isJUCEModulesFolder (const File&); -bool isJUCEFolder (const File&); - //============================================================================== struct ModuleDescription { - ModuleDescription() {} + ModuleDescription() = default; ModuleDescription (const File& folder); - ModuleDescription (const var& info) : moduleInfo (info) {} bool isValid() const { return getID().isNotEmpty(); } @@ -57,8 +52,6 @@ struct ModuleDescription File getFolder() const { jassert (moduleFolder != File()); return moduleFolder; } File getHeader() const; - bool isPluginClient() const { return getID() == "juce_audio_plugin_client"; } - File moduleFolder; var moduleInfo; URL url; @@ -91,7 +84,6 @@ public: File file; bool isCompiledForObjC, isCompiledForNonObjC; - void writeInclude (MemoryOutputStream&) const; bool isNeededForExporter (ProjectExporter&) const; String getFilenameForProxyFile() const; static bool hasSuffix (const File&, const char*); @@ -104,20 +96,25 @@ public: ModuleDescription moduleInfo; private: - mutable Array sourceFiles; - OwnedArray configFlags; + void addSearchPathsToExporter (ProjectExporter&) const; + void addDefinesToExporter (ProjectExporter&) const; + void addCompileUnitsToExporter (ProjectExporter&, ProjectSaver&) const; + void addLibsToExporter (ProjectExporter&) const; void addBrowseableCode (ProjectExporter&, const Array& compiled, const File& localModuleFolder) const; + + mutable Array sourceFiles; + OwnedArray configFlags; }; //============================================================================== -using ModuleIDAndFolder = std::pair; -using ModuleIDAndFolderList = std::vector; - class AvailableModuleList { public: - AvailableModuleList(); + using ModuleIDAndFolder = std::pair; + using ModuleIDAndFolderList = std::vector; + + AvailableModuleList() = default; void scanPaths (const Array&); void scanPathsAsync (const Array&); @@ -157,46 +154,49 @@ class EnabledModuleList public: EnabledModuleList (Project&, const ValueTree&); - static File findDefaultModulesFolder (Project&); - - bool isModuleEnabled (const String& moduleID) const; + //============================================================================== + ValueTree getState() const { return state; } - bool shouldUseGlobalPath (const String& moduleID) const; - Value getShouldUseGlobalPathValue (const String& moduleID) const; + StringArray getAllModules() const; + void createRequiredModules (OwnedArray& modules); + void sortAlphabetically(); - Value shouldShowAllModuleFilesInProject (const String& moduleID); - Value shouldCopyModuleFilesLocally (const String& moduleID) const; + File getDefaultModulesFolder() const; - void removeModule (String moduleID); - bool isAudioPluginModuleMissing() const; + int getNumModules() const { return state.getNumChildren(); } + String getModuleID (int index) const { return state.getChild (index) [Ids::ID].toString(); } ModuleDescription getModuleInfo (const String& moduleID); - void addModule (const File& moduleManifestFile, bool copyLocally, bool useGlobalPath, bool sendAnalyticsEvent); - void addModuleInteractive (const String& moduleID); - void addModuleFromUserSelectedFile(); - void addModuleOfferingToCopy (const File&, bool isFromUserSpecifiedFolder); - - StringArray getAllModules() const; + bool isModuleEnabled (const String& moduleID) const; StringArray getExtraDependenciesNeeded (const String& moduleID) const; bool doesModuleHaveHigherCppStandardThanProject (const String& moduleID); - void createRequiredModules (OwnedArray& modules); - int getNumModules() const { return state.getNumChildren(); } - String getModuleID (int index) const { return state.getChild (index) [Ids::ID].toString(); } + bool shouldUseGlobalPath (const String& moduleID) const; + Value shouldUseGlobalPathValue (const String& moduleID) const; + + bool shouldShowAllModuleFilesInProject (const String& moduleID) const; + Value shouldShowAllModuleFilesInProjectValue (const String& moduleID) const; + + bool shouldCopyModuleFilesLocally (const String& moduleID) const; + Value shouldCopyModuleFilesLocallyValue (const String& moduleID) const; bool areMostModulesUsingGlobalPath() const; bool areMostModulesCopiedLocally() const; - void setLocalCopyModeForAllModules (bool copyLocally); - - void sortAlphabetically(); + //============================================================================== + void addModule (const File& moduleManifestFile, bool copyLocally, bool useGlobalPath, bool sendAnalyticsEvent); + void addModuleInteractive (const String& moduleID); + void addModuleFromUserSelectedFile(); + void addModuleOfferingToCopy (const File&, bool isFromUserSpecifiedFolder); - Project& project; - ValueTree state; + void removeModule (String moduleID); private: UndoManager* getUndoManager() const { return project.getUndoManagerFor (state); } + Project& project; + ValueTree state; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModuleList) }; diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 9d760505d3..24d48f840b 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -2100,7 +2100,7 @@ void Project::rescanExporterPathModules (bool async) exporterPathsModuleList->scanPaths (getExporterModulePathsToScan (*this)); } -ModuleIDAndFolder Project::getModuleWithID (const String& id) +AvailableModuleList::ModuleIDAndFolder Project::getModuleWithID (const String& id) { if (! getEnabledModules().shouldUseGlobalPath (id)) { diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp index c90cd2d365..4274dd6cba 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp @@ -617,7 +617,7 @@ TargetOS::OS ProjectExporter::getTargetOSForExporter() const RelativePath ProjectExporter::getModuleFolderRelativeToProject (const String& moduleID) const { - if (project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID).getValue()) + if (project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID)) return RelativePath (project.getRelativePathForFile (project.getLocalModuleFolder (moduleID)), RelativePath::projectFolder); @@ -636,7 +636,7 @@ String ProjectExporter::getLegacyModulePath() const RelativePath ProjectExporter::getLegacyModulePath (const String& moduleID) const { - if (project.getEnabledModules().state.getChildWithProperty (Ids::ID, moduleID) ["useLocalCopy"]) + if (project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID)) return RelativePath (project.getRelativePathForFile (project.getGeneratedCodeFolder() .getChildFile ("modules") .getChildFile (moduleID)), RelativePath::projectFolder); diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp index c8879ca9e0..a9bb75facd 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp +++ b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp @@ -411,6 +411,16 @@ bool isValidJUCEExamplesDirectory (const File& directory) noexcept return directory.getChildFile ("Assets").getChildFile ("juce_icon.png").existsAsFile(); } +bool isJUCEFolder (const File& f) +{ + return isJUCEModulesFolder (f.getChildFile ("modules")); +} + +bool isJUCEModulesFolder (const File& f) +{ + return f.isDirectory() && f.getChildFile ("juce_core").isDirectory(); +} + //============================================================================== static var parseJUCEHeaderMetadata (const StringArray& lines) { diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h index f96b5ce18b..db6742da30 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h @@ -73,6 +73,9 @@ bool isPIPFile (const File&) noexcept; bool isValidJUCEExamplesDirectory (const File&) noexcept; +bool isJUCEModulesFolder (const File&); +bool isJUCEFolder (const File&); + //============================================================================== int indexOfLineStartingWith (const StringArray& lines, const String& text, int startIndex); diff --git a/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h b/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h index bda4a63a0a..7acd7ae451 100644 --- a/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h +++ b/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h @@ -87,7 +87,6 @@ public: void filesDropped (const StringArray& selectedFiles, int, int) override { - setTo (selectedFiles[0]); highlightForDragAndDrop = false;