mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-14 00:14:18 +00:00
544 lines
24 KiB
C++
544 lines
24 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
|
Copyright 2004-10 by Raw Material Software Ltd.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
JUCE can be redistributed and/or modified under the terms of the GNU General
|
|
Public License (Version 2), as published by the Free Software Foundation.
|
|
A copy of the license is included in the JUCE distribution, or can be found
|
|
online 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.rawmaterialsoftware.com/juce for more information.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
#ifndef __JUCER_PROJECTSAVER_JUCEHEADER__
|
|
#define __JUCER_PROJECTSAVER_JUCEHEADER__
|
|
|
|
|
|
//==============================================================================
|
|
class ProjectSaver
|
|
{
|
|
public:
|
|
ProjectSaver (Project& project_, const File& projectFile_)
|
|
: project (project_), projectFile (projectFile_), resourceFile (project_)
|
|
{
|
|
}
|
|
|
|
const String save()
|
|
{
|
|
const File oldFile (project.getFile());
|
|
project.setFile (projectFile);
|
|
|
|
const String linkageMode (project.getJuceLinkageMode());
|
|
|
|
if (linkageMode == Project::notLinkedToJuce)
|
|
{
|
|
hasAppHeaderFile = ! project.isLibrary();
|
|
hasAppConfigFile = false;
|
|
numJuceSourceFiles = 0;
|
|
}
|
|
else if (linkageMode == Project::useAmalgamatedJuce
|
|
|| linkageMode == Project::useAmalgamatedJuceViaSingleTemplate)
|
|
{
|
|
hasAppHeaderFile = true;
|
|
hasAppConfigFile = true;
|
|
numJuceSourceFiles = 1;
|
|
}
|
|
else if (linkageMode == Project::useAmalgamatedJuceViaMultipleTemplates)
|
|
{
|
|
hasAppHeaderFile = true;
|
|
hasAppConfigFile = true;
|
|
numJuceSourceFiles = project.getNumSeparateAmalgamatedFiles();
|
|
}
|
|
else if (linkageMode == Project::useLinkedJuce)
|
|
{
|
|
hasAppHeaderFile = true;
|
|
hasAppConfigFile = true;
|
|
numJuceSourceFiles = 0;
|
|
}
|
|
else
|
|
{
|
|
jassertfalse;
|
|
}
|
|
|
|
hasResources = (resourceFile.getNumFiles() > 0);
|
|
|
|
writeMainProjectFile();
|
|
|
|
if (errors.size() == 0)
|
|
writeJuceSourceWrappers();
|
|
|
|
if (errors.size() == 0)
|
|
writeProjects();
|
|
|
|
if (errors.size() > 0)
|
|
project.setFile (oldFile);
|
|
|
|
return errors[0];
|
|
}
|
|
|
|
private:
|
|
Project& project;
|
|
const File& projectFile;
|
|
ResourceFile resourceFile;
|
|
StringArray errors;
|
|
|
|
File appConfigFile, juceHeaderFile, binaryDataCpp, pluginCharacteristicsFile;
|
|
bool hasAppHeaderFile, hasAppConfigFile, hasResources;
|
|
int numJuceSourceFiles;
|
|
|
|
void writeMainProjectFile()
|
|
{
|
|
ScopedPointer <XmlElement> xml (project.getProjectRoot().createXml());
|
|
jassert (xml != 0);
|
|
|
|
if (xml != 0)
|
|
{
|
|
#if JUCE_DEBUG
|
|
{
|
|
MemoryOutputStream mo;
|
|
project.getProjectRoot().writeToStream (mo);
|
|
|
|
MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
|
|
ValueTree v = ValueTree::readFromStream (mi);
|
|
ScopedPointer <XmlElement> xml2 (v.createXml());
|
|
|
|
// This bit just tests that ValueTree save/load works reliably.. Let me know if this asserts for you!
|
|
jassert (xml->isEquivalentTo (xml2, true));
|
|
}
|
|
#endif
|
|
|
|
MemoryOutputStream mo;
|
|
xml->writeToStream (mo, String::empty);
|
|
|
|
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (projectFile, mo))
|
|
errors.add ("Couldn't write to the target file!");
|
|
}
|
|
}
|
|
|
|
void writeJucerComment (OutputStream& out)
|
|
{
|
|
out << "/*" << newLine << newLine
|
|
<< " IMPORTANT! This file is auto-generated by the Jucer each time you save your" << newLine
|
|
<< " project - if you alter its contents, your changes may be overwritten!" << newLine
|
|
<< newLine;
|
|
}
|
|
|
|
void writeAppConfig (OutputStream& out)
|
|
{
|
|
writeJucerComment (out);
|
|
out << " If you want to change any of these values, use the Jucer to do so, rather than" << newLine
|
|
<< " editing this file directly!" << newLine
|
|
<< newLine
|
|
<< " Any commented-out settings will fall back to using the default values that" << newLine
|
|
<< " they are given in juce_Config.h" << newLine
|
|
<< newLine
|
|
<< "*/" << newLine << newLine;
|
|
|
|
bool notActive = project.getJuceLinkageMode() == Project::useLinkedJuce
|
|
|| project.getJuceLinkageMode() == Project::notLinkedToJuce;
|
|
if (notActive)
|
|
out << "/* NOTE: These configs aren't available when you're linking to the juce library statically!" << newLine
|
|
<< " If you need to set a configuration that differs from the default, you'll need" << newLine
|
|
<< " to include the amalgamated Juce files." << newLine << newLine;
|
|
|
|
OwnedArray <Project::JuceConfigFlag> flags;
|
|
project.getJuceConfigFlags (flags);
|
|
|
|
for (int i = 0; i < flags.size(); ++i)
|
|
{
|
|
const Project::JuceConfigFlag* const f = flags[i];
|
|
const String value (f->value.toString());
|
|
|
|
if (value != Project::configFlagEnabled && value != Project::configFlagDisabled)
|
|
out << "//#define ";
|
|
else
|
|
out << "#define ";
|
|
|
|
out << f->symbol;
|
|
|
|
if (value == Project::configFlagEnabled)
|
|
out << " 1";
|
|
else if (value == Project::configFlagDisabled)
|
|
out << " 0";
|
|
|
|
out << newLine;
|
|
}
|
|
|
|
if (notActive)
|
|
out << newLine << "*/" << newLine;
|
|
}
|
|
|
|
void writeSourceWrapper (OutputStream& out, int fileNumber)
|
|
{
|
|
writeJucerComment (out);
|
|
out << " This file pulls in all the Juce source code, and builds it using the settings" << newLine
|
|
<< " defined in " << appConfigFile.getFileName() << "." << newLine
|
|
<< newLine
|
|
<< " If you want to change the method by which Juce is linked into your app, use the" << newLine
|
|
<< " Jucer to change it, rather than trying to edit this file directly." << newLine
|
|
<< newLine
|
|
<< "*/"
|
|
<< newLine << newLine
|
|
<< CodeHelpers::createIncludeStatement (appConfigFile, appConfigFile) << newLine;
|
|
|
|
if (fileNumber == 0)
|
|
writeInclude (out, project.isUsingFullyAmalgamatedFile() ? "juce_amalgamated.cpp"
|
|
: "amalgamation/juce_amalgamated_template.cpp");
|
|
else
|
|
writeInclude (out, "amalgamation/juce_amalgamated" + String (fileNumber) + ".cpp");
|
|
}
|
|
|
|
void writeAppHeader (OutputStream& out)
|
|
{
|
|
writeJucerComment (out);
|
|
out << " This is the header file that your files should include in order to get all the" << newLine
|
|
<< " Juce library headers. You should NOT include juce.h or juce_amalgamated.h directly in" << newLine
|
|
<< " your own source files, because that wouldn't pick up the correct Juce configuration" << newLine
|
|
<< " options for your app." << newLine
|
|
<< newLine
|
|
<< "*/" << newLine << newLine;
|
|
|
|
String headerGuard ("__APPHEADERFILE_" + String::toHexString (juceHeaderFile.hashCode()).toUpperCase() + "__");
|
|
out << "#ifndef " << headerGuard << newLine
|
|
<< "#define " << headerGuard << newLine << newLine;
|
|
|
|
if (hasAppConfigFile)
|
|
out << CodeHelpers::createIncludeStatement (appConfigFile, appConfigFile) << newLine;
|
|
|
|
if (project.getJuceLinkageMode() != Project::notLinkedToJuce)
|
|
{
|
|
writeInclude (out, (project.isUsingSingleTemplateFile() || project.isUsingMultipleTemplateFiles())
|
|
? "juce_amalgamated.h" // could use "amalgamation/juce_amalgamated_template.h", but it's slower..
|
|
: (project.isUsingFullyAmalgamatedFile()
|
|
? "juce_amalgamated.h"
|
|
: "juce.h"));
|
|
}
|
|
|
|
if (binaryDataCpp.exists())
|
|
out << CodeHelpers::createIncludeStatement (binaryDataCpp.withFileExtension (".h"), appConfigFile) << newLine;
|
|
|
|
out << newLine
|
|
<< "namespace ProjectInfo" << newLine
|
|
<< "{" << newLine
|
|
<< " const char* const projectName = " << CodeHelpers::addEscapeChars (project.getProjectName().toString()).quoted() << ";" << newLine
|
|
<< " const char* const versionString = " << CodeHelpers::addEscapeChars (project.getVersion().toString()).quoted() << ";" << newLine
|
|
<< " const int versionNumber = " << createVersionCode (project.getVersion().toString()) << ";" << newLine
|
|
<< "}" << newLine
|
|
<< newLine
|
|
<< "#endif // " << headerGuard << newLine;
|
|
}
|
|
|
|
void writeInclude (OutputStream& out, const String& pathFromJuceFolder)
|
|
{
|
|
StringArray paths, guards;
|
|
|
|
for (int i = project.getNumExporters(); --i >= 0;)
|
|
{
|
|
ScopedPointer <ProjectExporter> exporter (project.createExporter (i));
|
|
|
|
if (exporter != 0)
|
|
{
|
|
paths.add (exporter->getIncludePathForFileInJuceFolder (pathFromJuceFolder, juceHeaderFile));
|
|
guards.add ("defined (" + exporter->getExporterIdentifierMacro() + ")");
|
|
}
|
|
}
|
|
|
|
StringArray uniquePaths (paths);
|
|
uniquePaths.removeDuplicates (false);
|
|
|
|
if (uniquePaths.size() == 1)
|
|
{
|
|
out << "#include " << paths[0] << newLine;
|
|
}
|
|
else
|
|
{
|
|
int i = paths.size();
|
|
for (; --i >= 0;)
|
|
{
|
|
for (int j = i; --j >= 0;)
|
|
{
|
|
if (paths[i] == paths[j] && guards[i] == guards[j])
|
|
{
|
|
paths.remove (i);
|
|
guards.remove (i);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < paths.size(); ++i)
|
|
{
|
|
out << (i == 0 ? "#if " : "#elif ") << guards[i] << newLine
|
|
<< " #include " << paths[i] << newLine;
|
|
}
|
|
|
|
out << "#endif" << newLine;
|
|
}
|
|
}
|
|
|
|
static int countMaxPluginChannels (const String& configString, bool isInput)
|
|
{
|
|
StringArray configs;
|
|
configs.addTokens (configString, ", {}", String::empty);
|
|
configs.trim();
|
|
configs.removeEmptyStrings();
|
|
jassert ((configs.size() & 1) == 0); // looks like a syntax error in the configs?
|
|
|
|
int maxVal = 0;
|
|
for (int i = (isInput ? 0 : 1); i < configs.size(); i += 2)
|
|
maxVal = jmax (maxVal, configs[i].getIntValue());
|
|
|
|
return maxVal;
|
|
}
|
|
|
|
static const String createVersionCode (const String& version)
|
|
{
|
|
StringArray configs;
|
|
configs.addTokens (version, ",.", String::empty);
|
|
configs.trim();
|
|
configs.removeEmptyStrings();
|
|
|
|
int value = (configs[0].getIntValue() << 16) + (configs[1].getIntValue() << 8) + configs[2].getIntValue();
|
|
|
|
if (configs.size() >= 4)
|
|
value = (value << 8) + configs[3].getIntValue();
|
|
|
|
return "0x" + String::toHexString (value);
|
|
}
|
|
|
|
void writePluginCharacteristics (OutputStream& out)
|
|
{
|
|
String headerGuard ("__PLUGINCHARACTERISTICS_" + String::toHexString (pluginCharacteristicsFile.hashCode()).toUpperCase() + "__");
|
|
|
|
writeJucerComment (out);
|
|
out << " This header file contains configuration options for the plug-in. If you need to change any of" << newLine
|
|
<< " these, it'd be wise to do so using the Jucer, rather than editing this file directly..." << newLine
|
|
<< newLine
|
|
<< "*/" << newLine
|
|
<< newLine
|
|
<< "#ifndef " << headerGuard << newLine
|
|
<< "#define " << headerGuard << newLine
|
|
<< newLine
|
|
<< "#define JucePlugin_Build_VST " << ((bool) project.shouldBuildVST().getValue() ? 1 : 0) << " // (If you change this value, you'll also need to re-export the projects using the Jucer)" << newLine
|
|
<< "#define JucePlugin_Build_AU " << ((bool) project.shouldBuildAU().getValue() ? 1 : 0) << " // (If you change this value, you'll also need to re-export the projects using the Jucer)" << newLine
|
|
<< "#define JucePlugin_Build_RTAS " << ((bool) project.shouldBuildRTAS().getValue() ? 1 : 0) << " // (If you change this value, you'll also need to re-export the projects using the Jucer)" << newLine
|
|
<< newLine
|
|
<< "#define JucePlugin_Name " << project.getPluginName().toString().quoted() << newLine
|
|
<< "#define JucePlugin_Desc " << project.getPluginDesc().toString().quoted() << newLine
|
|
<< "#define JucePlugin_Manufacturer " << project.getPluginManufacturer().toString().quoted() << newLine
|
|
<< "#define JucePlugin_ManufacturerCode '" << project.getPluginManufacturerCode().toString().trim().substring (0, 4) << "'" << newLine
|
|
<< "#define JucePlugin_PluginCode '" << project.getPluginCode().toString().trim().substring (0, 4) << "'" << newLine
|
|
<< "#define JucePlugin_MaxNumInputChannels " << countMaxPluginChannels (project.getPluginChannelConfigs().toString(), true) << newLine
|
|
<< "#define JucePlugin_MaxNumOutputChannels " << countMaxPluginChannels (project.getPluginChannelConfigs().toString(), false) << newLine
|
|
<< "#define JucePlugin_PreferredChannelConfigurations " << project.getPluginChannelConfigs().toString() << newLine
|
|
<< "#define JucePlugin_IsSynth " << ((bool) project.getPluginIsSynth().getValue() ? 1 : 0) << newLine
|
|
<< "#define JucePlugin_WantsMidiInput " << ((bool) project.getPluginWantsMidiInput().getValue() ? 1 : 0) << newLine
|
|
<< "#define JucePlugin_ProducesMidiOutput " << ((bool) project.getPluginProducesMidiOut().getValue() ? 1 : 0) << newLine
|
|
<< "#define JucePlugin_SilenceInProducesSilenceOut " << ((bool) project.getPluginSilenceInProducesSilenceOut().getValue() ? 1 : 0) << newLine
|
|
<< "#define JucePlugin_TailLengthSeconds " << (double) project.getPluginTailLengthSeconds().getValue() << newLine
|
|
<< "#define JucePlugin_EditorRequiresKeyboardFocus " << ((bool) project.getPluginEditorNeedsKeyFocus().getValue() ? 1 : 0) << newLine
|
|
<< "#define JucePlugin_VersionCode " << createVersionCode (project.getVersion().toString()) << newLine
|
|
<< "#define JucePlugin_VersionString " << project.getVersion().toString().quoted() << newLine
|
|
<< "#define JucePlugin_VSTUniqueID JucePlugin_PluginCode" << newLine
|
|
<< "#define JucePlugin_VSTCategory " << ((bool) project.getPluginIsSynth().getValue() ? "kPlugCategSynth" : "kPlugCategEffect") << newLine
|
|
<< "#define JucePlugin_AUMainType " << ((bool) project.getPluginIsSynth().getValue() ? "kAudioUnitType_MusicDevice" : "kAudioUnitType_Effect") << newLine
|
|
<< "#define JucePlugin_AUSubType JucePlugin_PluginCode" << newLine
|
|
<< "#define JucePlugin_AUExportPrefix " << project.getPluginAUExportPrefix().toString() << newLine
|
|
<< "#define JucePlugin_AUExportPrefixQuoted " << project.getPluginAUExportPrefix().toString().quoted() << newLine
|
|
<< "#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode" << newLine
|
|
<< "#define JucePlugin_CFBundleIdentifier " << project.getBundleIdentifier().toString() << newLine
|
|
<< "#define JucePlugin_AUCocoaViewClassName " << project.getPluginAUCocoaViewClassName().toString() << newLine
|
|
<< "#define JucePlugin_RTASCategory " << ((bool) project.getPluginIsSynth().getValue() ? "ePlugInCategory_SWGenerators" : "ePlugInCategory_None") << newLine
|
|
<< "#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode" << newLine
|
|
<< "#define JucePlugin_RTASProductId JucePlugin_PluginCode" << newLine;
|
|
|
|
out << "#define JUCE_USE_VSTSDK_2_4 1" << newLine
|
|
<< newLine
|
|
<< "#endif // " << headerGuard << newLine;
|
|
}
|
|
|
|
bool replaceFileIfDifferent (const File& f, const MemoryOutputStream& newData)
|
|
{
|
|
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (f, newData))
|
|
{
|
|
errors.add ("Can't write to file: " + f.getFullPathName());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void writeJuceSourceWrappers()
|
|
{
|
|
const File wrapperFolder (project.getWrapperFolder());
|
|
|
|
appConfigFile = wrapperFolder.getChildFile (project.getAppConfigFilename());
|
|
pluginCharacteristicsFile = wrapperFolder.getChildFile (project.getPluginCharacteristicsFilename());
|
|
|
|
juceHeaderFile = project.getAppIncludeFile();
|
|
binaryDataCpp = wrapperFolder.getChildFile ("BinaryData.cpp");
|
|
|
|
if (resourceFile.getNumFiles() > 0)
|
|
{
|
|
if (! wrapperFolder.createDirectory())
|
|
{
|
|
errors.add ("Couldn't create folder: " + wrapperFolder.getFullPathName());
|
|
return;
|
|
}
|
|
|
|
//resourceFile.setJuceHeaderToInclude (juceHeaderFile);
|
|
resourceFile.setClassName ("BinaryData");
|
|
|
|
if (! resourceFile.write (binaryDataCpp))
|
|
errors.add ("Can't create binary resources file: " + binaryDataCpp.getFullPathName());
|
|
}
|
|
else
|
|
{
|
|
binaryDataCpp.deleteFile();
|
|
binaryDataCpp.withFileExtension ("h").deleteFile();
|
|
}
|
|
|
|
if (project.isLibrary())
|
|
return;
|
|
|
|
if (! wrapperFolder.createDirectory())
|
|
{
|
|
errors.add ("Couldn't create folder: " + wrapperFolder.getFullPathName());
|
|
return;
|
|
}
|
|
|
|
if (hasAppConfigFile)
|
|
{
|
|
MemoryOutputStream mem;
|
|
writeAppConfig (mem);
|
|
replaceFileIfDifferent (appConfigFile, mem);
|
|
}
|
|
else
|
|
{
|
|
appConfigFile.deleteFile();
|
|
}
|
|
|
|
if (project.isAudioPlugin())
|
|
{
|
|
MemoryOutputStream mem;
|
|
writePluginCharacteristics (mem);
|
|
replaceFileIfDifferent (pluginCharacteristicsFile, mem);
|
|
}
|
|
|
|
for (int i = 0; i <= project.getNumSeparateAmalgamatedFiles(); ++i)
|
|
{
|
|
const File sourceWrapperCpp (getSourceWrapperCpp (i));
|
|
const File sourceWrapperMM (sourceWrapperCpp.withFileExtension (".mm"));
|
|
|
|
if (numJuceSourceFiles > 0
|
|
&& ((i == 0 && numJuceSourceFiles == 1) || (i != 0 && numJuceSourceFiles > 1)))
|
|
{
|
|
MemoryOutputStream mem;
|
|
writeSourceWrapper (mem, i);
|
|
replaceFileIfDifferent (sourceWrapperCpp, mem);
|
|
replaceFileIfDifferent (sourceWrapperMM, mem);
|
|
}
|
|
else
|
|
{
|
|
sourceWrapperMM.deleteFile();
|
|
sourceWrapperCpp.deleteFile();
|
|
}
|
|
}
|
|
|
|
if (hasAppHeaderFile)
|
|
{
|
|
MemoryOutputStream mem;
|
|
writeAppHeader (mem);
|
|
replaceFileIfDifferent (juceHeaderFile, mem);
|
|
}
|
|
else
|
|
{
|
|
juceHeaderFile.deleteFile();
|
|
}
|
|
}
|
|
|
|
void writeProjects()
|
|
{
|
|
for (int i = project.getNumExporters(); --i >= 0;)
|
|
{
|
|
ScopedPointer <ProjectExporter> exporter (project.createExporter (i));
|
|
std::cout << "Writing files for: " << exporter->getName() << std::endl;
|
|
|
|
const File targetFolder (exporter->getTargetFolder());
|
|
|
|
if (targetFolder.createDirectory())
|
|
{
|
|
exporter->juceWrapperFolder = RelativePath (project.getWrapperFolder(), targetFolder, RelativePath::buildTargetFolder);
|
|
|
|
if (hasAppConfigFile)
|
|
exporter->juceWrapperFiles.add (RelativePath (appConfigFile, targetFolder, RelativePath::buildTargetFolder));
|
|
|
|
if (hasAppHeaderFile)
|
|
exporter->juceWrapperFiles.add (RelativePath (juceHeaderFile, targetFolder, RelativePath::buildTargetFolder));
|
|
|
|
if (hasResources)
|
|
{
|
|
exporter->juceWrapperFiles.add (RelativePath (binaryDataCpp, targetFolder, RelativePath::buildTargetFolder));
|
|
exporter->juceWrapperFiles.add (RelativePath (binaryDataCpp, targetFolder, RelativePath::buildTargetFolder)
|
|
.withFileExtension (".h"));
|
|
}
|
|
|
|
if (numJuceSourceFiles > 0)
|
|
{
|
|
for (int j = 0; j <= project.getNumSeparateAmalgamatedFiles(); ++j)
|
|
{
|
|
const File sourceWrapperCpp (getSourceWrapperCpp (j));
|
|
const File sourceWrapperMM (sourceWrapperCpp.withFileExtension (".mm"));
|
|
|
|
if ((j == 0 && numJuceSourceFiles == 1) || (j != 0 && numJuceSourceFiles > 1))
|
|
{
|
|
if (exporter->usesMMFiles())
|
|
exporter->juceWrapperFiles.add (RelativePath (sourceWrapperMM, targetFolder, RelativePath::buildTargetFolder));
|
|
else
|
|
exporter->juceWrapperFiles.add (RelativePath (sourceWrapperCpp, targetFolder, RelativePath::buildTargetFolder));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (project.isAudioPlugin())
|
|
exporter->juceWrapperFiles.add (RelativePath (pluginCharacteristicsFile, targetFolder, RelativePath::buildTargetFolder));
|
|
|
|
try
|
|
{
|
|
exporter->create();
|
|
}
|
|
catch (ProjectExporter::SaveError& error)
|
|
{
|
|
errors.add (error.message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errors.add ("Can't create folder: " + exporter->getTargetFolder().getFullPathName());
|
|
}
|
|
}
|
|
}
|
|
|
|
const File getSourceWrapperCpp (int fileIndex) const
|
|
{
|
|
return project.getWrapperFolder().getChildFile (project.getJuceSourceFilenameRoot() + (fileIndex != 0 ? String (fileIndex) : String::empty))
|
|
.withFileExtension (".cpp");
|
|
}
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectSaver);
|
|
};
|
|
|
|
|
|
#endif
|