Browse Source

Projucer: Refactored the module handling code

tags/2021-05-28
ed 5 years ago
parent
commit
c73c5512d5
11 changed files with 316 additions and 309 deletions
  1. +2
    -8
      extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h
  2. +4
    -4
      extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp
  3. +16
    -10
      extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h
  4. +18
    -11
      extras/Projucer/Source/Project/UI/jucer_ModulesInformationComponent.h
  5. +222
    -234
      extras/Projucer/Source/Project/jucer_Module.cpp
  6. +38
    -38
      extras/Projucer/Source/Project/jucer_Module.h
  7. +1
    -1
      extras/Projucer/Source/Project/jucer_Project.cpp
  8. +2
    -2
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp
  9. +10
    -0
      extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp
  10. +3
    -0
      extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h
  11. +0
    -1
      extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h

+ 2
- 8
extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h View File

@@ -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


+ 4
- 4
extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp View File

@@ -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


+ 16
- 10
extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h View File

@@ -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<ValueWithDefault> exporterModulePathDefaultValues;
Array<Value> exporterModulePathValues;
Value globalPathValue;
Array<Value> exporterModulePathValues, globalPathValues;
Value useGlobalPathValue;
OwnedArray <Project::ConfigFlag> 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<ModuleIDAndFolder> list;
std::vector<AvailableModuleList::ModuleIDAndFolder> list;
int offset = -1;
if (resultCode < 200)


+ 18
- 11
extras/Projucer/Source/Project/UI/jucer_ModulesInformationComponent.h View File

@@ -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<int> 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()


+ 222
- 234
extras/Projucer/Source/Project/jucer_Module.cpp View File

@@ -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<File>& paths, std::function<void (const ModuleIDAndFolderList&)>&& callback)
ModuleScannerJob (const Array<File>& paths,
std::function<void (const AvailableModuleList::ModuleIDAndFolderList&)>&& 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<File> pathsToScan;
std::function<void (const ModuleIDAndFolderList&)> completionCallback;
std::function<void (const AvailableModuleList::ModuleIDAndFolderList&)> completionCallback;
};
AvailableModuleList::AvailableModuleList()
{
}
ThreadPoolJob* AvailableModuleList::createScannerJob (const Array<File>& 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<File>& 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<File> 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<File> 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<Project::ConfigFlag>& flags) const
{
auto header = moduleInfo.getHeader();
@@ -384,7 +391,25 @@ void LibraryModule::getConfigFlags (Project& project, OwnedArray<Project::Config
}
}
//==============================================================================
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);
}
}
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<File>& filesFound) const
{
auto fileWithoutSuffix = f.getFileNameWithoutExtension() + ".";
Array<File> 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::CompileUnit> 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<File>& filesFound) const
{
Array<File> 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<File>& compiled, const File& localModuleFolder) const
{
if (sourceFiles.isEmpty())
@@ -531,7 +533,7 @@ void LibraryModule::addBrowseableCode (ProjectExporter& exporter, const Array<Fi
auto& project = exporter.getProject();
if (project.getEnabledModules().shouldCopyModuleFilesLocally (getID()).getValue())
if (project.getEnabledModules().shouldCopyModuleFilesLocally (getID()))
moduleHeader = project.getLocalModuleFolder (getID()).getChildFile (moduleHeader.getFileName());
auto isModuleHeader = [&] (const File& f) { return f.getFileName() == moduleHeader.getFileName(); };
@@ -552,131 +554,68 @@ void LibraryModule::addBrowseableCode (ProjectExporter& exporter, const Array<Fi
exporter.getModulesGroup().state.appendChild (sourceGroup.state.createCopy(), nullptr);
}
//==============================================================================
EnabledModuleList::EnabledModuleList (Project& p, const ValueTree& s)
: project (p), state (s)
{
}
ModuleDescription EnabledModuleList::getModuleInfo (const String& moduleID)
{
return ModuleDescription (project.getModuleWithID (moduleID).second);
}
bool EnabledModuleList::isModuleEnabled (const String& moduleID) const
{
return state.getChildWithProperty (Ids::ID, moduleID).isValid();
}
bool EnabledModuleList::isAudioPluginModuleMissing() const
StringArray EnabledModuleList::getAllModules() const
{
return project.isAudioPluginProject()
&& ! isModuleEnabled ("juce_audio_plugin_client");
}
StringArray moduleIDs;
bool EnabledModuleList::shouldUseGlobalPath (const String& moduleID) const
{
return static_cast<bool> (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<LibraryModule>& 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<LibraryModule>& 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);
}

+ 38
- 38
extras/Projucer/Source/Project/jucer_Module.h View File

@@ -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<File> sourceFiles;
OwnedArray<Project::ConfigFlag> configFlags;
void addSearchPathsToExporter (ProjectExporter&) const;
void addDefinesToExporter (ProjectExporter&) const;
void addCompileUnitsToExporter (ProjectExporter&, ProjectSaver&) const;
void addLibsToExporter (ProjectExporter&) const;
void addBrowseableCode (ProjectExporter&, const Array<File>& compiled, const File& localModuleFolder) const;
mutable Array<File> sourceFiles;
OwnedArray<Project::ConfigFlag> configFlags;
};
//==============================================================================
using ModuleIDAndFolder = std::pair<String, File>;
using ModuleIDAndFolderList = std::vector<ModuleIDAndFolder>;
class AvailableModuleList
{
public:
AvailableModuleList();
using ModuleIDAndFolder = std::pair<String, File>;
using ModuleIDAndFolderList = std::vector<ModuleIDAndFolder>;
AvailableModuleList() = default;
void scanPaths (const Array<File>&);
void scanPathsAsync (const Array<File>&);
@@ -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<LibraryModule>& 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<LibraryModule>& 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)
};

+ 1
- 1
extras/Projucer/Source/Project/jucer_Project.cpp View File

@@ -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))
{


+ 2
- 2
extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp View File

@@ -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);


+ 10
- 0
extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.cpp View File

@@ -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)
{


+ 3
- 0
extras/Projucer/Source/Utility/Helpers/jucer_MiscUtilities.h View File

@@ -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);


+ 0
- 1
extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h View File

@@ -87,7 +87,6 @@ public:
void filesDropped (const StringArray& selectedFiles, int, int) override
{
setTo (selectedFiles[0]);
highlightForDragAndDrop = false;


Loading…
Cancel
Save