build(deps): vendor JUCE 7.0.12

This commit is contained in:
2026-09-08 14:55:21 +02:00
parent 5b99f51bd1
commit d6705ab29f
3591 changed files with 1218267 additions and 0 deletions
@@ -0,0 +1,301 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "../../Application/jucer_Headers.h"
#include "jucer_CodeHelpers.h"
//==============================================================================
namespace CodeHelpers
{
String indent (const String& code, const int numSpaces, bool indentFirstLine)
{
if (numSpaces == 0)
return code;
auto space = String::repeatedString (" ", numSpaces);
auto lines = StringArray::fromLines (code);
for (auto& line : lines)
{
if (! indentFirstLine)
{
indentFirstLine = true;
continue;
}
if (line.trimEnd().isNotEmpty())
line = space + line;
}
return lines.joinIntoString (newLine);
}
String unindent (const String& code, const int numSpaces)
{
if (numSpaces == 0)
return code;
auto space = String::repeatedString (" ", numSpaces);
auto lines = StringArray::fromLines (code);
for (auto& line : lines)
if (line.startsWith (space))
line = line.substring (numSpaces);
return lines.joinIntoString (newLine);
}
String createIncludeStatement (const File& includeFile, const File& targetFile)
{
return createIncludeStatement (build_tools::unixStylePath (build_tools::getRelativePathFrom (includeFile, targetFile.getParentDirectory())));
}
String createIncludeStatement (const String& includePath)
{
if (includePath.startsWithChar ('<') || includePath.startsWithChar ('"'))
return "#include " + includePath;
return "#include \"" + includePath + "\"";
}
String createIncludePathIncludeStatement (const String& includedFilename)
{
return "#include <" + includedFilename + ">";
}
String stringLiteral (const String& text, int maxLineLength)
{
if (text.isEmpty())
return "juce::String()";
StringArray lines;
{
auto t = text.getCharPointer();
bool finished = t.isEmpty();
while (! finished)
{
for (auto startOfLine = t;;)
{
switch (t.getAndAdvance())
{
case 0: finished = true; break;
case '\n': break;
case '\r': if (*t == '\n') ++t; break;
default: continue;
}
lines.add (String (startOfLine, t));
break;
}
}
}
if (maxLineLength > 0)
{
for (int i = 0; i < lines.size(); ++i)
{
auto& line = lines.getReference (i);
if (line.length() > maxLineLength)
{
const String start (line.substring (0, maxLineLength));
const String end (line.substring (maxLineLength));
line = start;
lines.insert (i + 1, end);
}
}
}
for (int i = 0; i < lines.size(); ++i)
lines.getReference (i) = CppTokeniserFunctions::addEscapeChars (lines.getReference (i));
lines.removeEmptyStrings();
for (int i = 0; i < lines.size(); ++i)
lines.getReference (i) = "\"" + lines.getReference (i) + "\"";
String result (lines.joinIntoString (newLine));
if (! CharPointer_ASCII::isValidString (text.toUTF8(), std::numeric_limits<int>::max()))
result = "juce::CharPointer_UTF8 (" + result + ")";
return result;
}
String alignFunctionCallParams (const String& call, const StringArray& parameters, const int maxLineLength)
{
String result, currentLine (call);
for (int i = 0; i < parameters.size(); ++i)
{
if (currentLine.length() >= maxLineLength)
{
result += currentLine.trimEnd() + newLine;
currentLine = String::repeatedString (" ", call.length()) + parameters[i];
}
else
{
currentLine += parameters[i];
}
if (i < parameters.size() - 1)
currentLine << ", ";
}
return result + currentLine.trimEnd() + ")";
}
String floatLiteral (double value, int numDecPlaces)
{
String s (value, numDecPlaces);
if (s.containsChar ('.'))
s << 'f';
else
s << ".0f";
return s;
}
String boolLiteral (bool value)
{
return value ? "true" : "false";
}
String colourToCode (Colour col)
{
const Colour colours[] =
{
#define COL(col) Colours::col,
#include "jucer_Colours.h"
#undef COL
Colours::transparentBlack
};
static const char* colourNames[] =
{
#define COL(col) #col,
#include "jucer_Colours.h"
#undef COL
nullptr
};
for (int i = 0; i < numElementsInArray (colourNames) - 1; ++i)
if (col == colours[i])
return "juce::Colours::" + String (colourNames[i]);
return "juce::Colour (0x" + build_tools::hexString8Digits ((int) col.getARGB()) + ')';
}
String justificationToCode (Justification justification)
{
switch (justification.getFlags())
{
case Justification::centred: return "juce::Justification::centred";
case Justification::centredLeft: return "juce::Justification::centredLeft";
case Justification::centredRight: return "juce::Justification::centredRight";
case Justification::centredTop: return "juce::Justification::centredTop";
case Justification::centredBottom: return "juce::Justification::centredBottom";
case Justification::topLeft: return "juce::Justification::topLeft";
case Justification::topRight: return "juce::Justification::topRight";
case Justification::bottomLeft: return "juce::Justification::bottomLeft";
case Justification::bottomRight: return "juce::Justification::bottomRight";
case Justification::left: return "juce::Justification::left";
case Justification::right: return "juce::Justification::right";
case Justification::horizontallyCentred: return "juce::Justification::horizontallyCentred";
case Justification::top: return "juce::Justification::top";
case Justification::bottom: return "juce::Justification::bottom";
case Justification::verticallyCentred: return "juce::Justification::verticallyCentred";
case Justification::horizontallyJustified: return "juce::Justification::horizontallyJustified";
default: break;
}
jassertfalse;
return "Justification (" + String (justification.getFlags()) + ")";
}
//==============================================================================
String getLeadingWhitespace (String line)
{
line = line.removeCharacters (line.endsWith ("\r\n") ? "\r\n" : "\n");
auto endOfLeadingWS = line.getCharPointer().findEndOfWhitespace();
return String (line.getCharPointer(), endOfLeadingWS);
}
int getBraceCount (String::CharPointerType line)
{
int braces = 0;
for (;;)
{
const juce_wchar c = line.getAndAdvance();
if (c == 0) break;
else if (c == '{') ++braces;
else if (c == '}') --braces;
else if (c == '/') { if (*line == '/') break; }
else if (c == '"' || c == '\'') { while (! (line.isEmpty() || line.getAndAdvance() == c)) {} }
}
return braces;
}
bool getIndentForCurrentBlock (CodeDocument::Position pos, const String& tab,
String& blockIndent, String& lastLineIndent)
{
int braceCount = 0;
bool indentFound = false;
while (pos.getLineNumber() > 0)
{
pos = pos.movedByLines (-1);
auto line = pos.getLineText();
auto trimmedLine = line.trimStart();
braceCount += getBraceCount (trimmedLine.getCharPointer());
if (braceCount > 0)
{
blockIndent = getLeadingWhitespace (line);
if (! indentFound)
lastLineIndent = blockIndent + tab;
return true;
}
if ((! indentFound) && trimmedLine.isNotEmpty())
{
indentFound = true;
lastLineIndent = getLeadingWhitespace (line);
}
}
return false;
}
}
@@ -0,0 +1,52 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
namespace CodeHelpers
{
String indent (const String& code, int numSpaces, bool indentFirstLine);
String unindent (const String& code, int numSpaces);
String createIncludeStatement (const File& includedFile, const File& targetFile);
String createIncludeStatement (const String& includePath);
String createIncludePathIncludeStatement (const String& includedFilename);
String stringLiteral (const String& text, int maxLineLength = -1);
String floatLiteral (double value, int numDecPlaces);
String boolLiteral (bool value);
String colourToCode (Colour);
String justificationToCode (Justification);
String alignFunctionCallParams (const String& call, const StringArray& parameters, int maxLineLength);
String getLeadingWhitespace (String line);
int getBraceCount (String::CharPointerType line);
bool getIndentForCurrentBlock (CodeDocument::Position pos, const String& tab,
String& blockIndent, String& lastLineIndent);
}
@@ -0,0 +1,162 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
COL (black)
COL (white)
COL (blue)
COL (grey)
COL (green)
COL (red)
COL (yellow)
COL (aliceblue)
COL (antiquewhite)
COL (aqua)
COL (aquamarine)
COL (azure)
COL (beige)
COL (bisque)
COL (blanchedalmond)
COL (blueviolet)
COL (brown)
COL (burlywood)
COL (cadetblue)
COL (chartreuse)
COL (chocolate)
COL (coral)
COL (cornflowerblue)
COL (cornsilk)
COL (crimson)
COL (cyan)
COL (darkblue)
COL (darkcyan)
COL (darkgoldenrod)
COL (darkgrey)
COL (darkgreen)
COL (darkkhaki)
COL (darkmagenta)
COL (darkolivegreen)
COL (darkorange)
COL (darkorchid)
COL (darkred)
COL (darksalmon)
COL (darkseagreen)
COL (darkslateblue)
COL (darkslategrey)
COL (darkturquoise)
COL (darkviolet)
COL (deeppink)
COL (deepskyblue)
COL (dimgrey)
COL (dodgerblue)
COL (firebrick)
COL (floralwhite)
COL (forestgreen)
COL (fuchsia)
COL (gainsboro)
COL (gold)
COL (goldenrod)
COL (greenyellow)
COL (honeydew)
COL (hotpink)
COL (indianred)
COL (indigo)
COL (ivory)
COL (khaki)
COL (lavender)
COL (lavenderblush)
COL (lemonchiffon)
COL (lightblue)
COL (lightcoral)
COL (lightcyan)
COL (lightgoldenrodyellow)
COL (lightgreen)
COL (lightgrey)
COL (lightpink)
COL (lightsalmon)
COL (lightseagreen)
COL (lightskyblue)
COL (lightslategrey)
COL (lightsteelblue)
COL (lightyellow)
COL (lime)
COL (limegreen)
COL (linen)
COL (magenta)
COL (maroon)
COL (mediumaquamarine)
COL (mediumblue)
COL (mediumorchid)
COL (mediumpurple)
COL (mediumseagreen)
COL (mediumslateblue)
COL (mediumspringgreen)
COL (mediumturquoise)
COL (mediumvioletred)
COL (midnightblue)
COL (mintcream)
COL (mistyrose)
COL (navajowhite)
COL (navy)
COL (oldlace)
COL (olive)
COL (olivedrab)
COL (orange)
COL (orangered)
COL (orchid)
COL (palegoldenrod)
COL (palegreen)
COL (paleturquoise)
COL (palevioletred)
COL (papayawhip)
COL (peachpuff)
COL (peru)
COL (pink)
COL (plum)
COL (powderblue)
COL (purple)
COL (rosybrown)
COL (royalblue)
COL (saddlebrown)
COL (salmon)
COL (sandybrown)
COL (seagreen)
COL (seashell)
COL (sienna)
COL (silver)
COL (skyblue)
COL (slateblue)
COL (slategrey)
COL (snow)
COL (springgreen)
COL (steelblue)
COL (tan)
COL (teal)
COL (thistle)
COL (tomato)
COL (turquoise)
COL (violet)
COL (wheat)
COL (whitesmoke)
COL (yellowgreen)
@@ -0,0 +1,107 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "../../Application/jucer_Headers.h"
#include "jucer_CodeHelpers.h"
//==============================================================================
namespace FileHelpers
{
bool containsAnyNonHiddenFiles (const File& folder)
{
for (const auto& di : RangedDirectoryIterator (folder, false))
if (! di.getFile().isHidden())
return true;
return false;
}
bool shouldPathsBeRelative (String path1, String path2)
{
path1 = build_tools::unixStylePath (path1);
path2 = build_tools::unixStylePath (path2);
const int len = jmin (path1.length(), path2.length());
int commonBitLength = 0;
for (int i = 0; i < len; ++i)
{
if (CharacterFunctions::toLowerCase (path1[i]) != CharacterFunctions::toLowerCase (path2[i]))
break;
++commonBitLength;
}
return path1.substring (0, commonBitLength).removeCharacters ("/:").isNotEmpty();
}
// removes "/../" bits from the middle of the path
String simplifyPath (String::CharPointerType p)
{
#if JUCE_WINDOWS
if (CharacterFunctions::indexOf (p, CharPointer_ASCII ("/../")) >= 0
|| CharacterFunctions::indexOf (p, CharPointer_ASCII ("\\..\\")) >= 0)
#else
if (CharacterFunctions::indexOf (p, CharPointer_ASCII ("/../")) >= 0)
#endif
{
StringArray toks;
#if JUCE_WINDOWS
toks.addTokens (p, "\\/", StringRef());
#else
toks.addTokens (p, "/", StringRef());
#endif
while (toks[0] == ".")
toks.remove (0);
for (int i = 1; i < toks.size(); ++i)
{
if (toks[i] == ".." && toks [i - 1] != "..")
{
toks.removeRange (i - 1, 2);
i = jmax (0, i - 2);
}
}
return toks.joinIntoString ("/");
}
return p;
}
String simplifyPath (const String& path)
{
#if JUCE_WINDOWS
if (path.contains ("\\..\\") || path.contains ("/../"))
#else
if (path.contains ("/../"))
#endif
return simplifyPath (path.getCharPointer());
return path;
}
}
@@ -0,0 +1,79 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
namespace FileHelpers
{
bool containsAnyNonHiddenFiles (const File& folder);
bool shouldPathsBeRelative (String path1, String path2);
// removes "/../" bits from the middle of the path
String simplifyPath (String::CharPointerType path);
String simplifyPath (const String& path);
}
//==============================================================================
const char* const sourceFileExtensions = "cpp;mm;m;metal;c;cc;cxx;swift;s;asm;r";
const char* const headerFileExtensions = "h;hpp;hxx;hh;inl";
const char* const cOrCppFileExtensions = "cpp;cc;cxx;c";
const char* const cppFileExtensions = "cpp;cc;cxx";
const char* const objCFileExtensions = "mm;m";
const char* const asmFileExtensions = "s;S;asm";
const char* const sourceOrHeaderFileExtensions = "cpp;mm;m;metal;c;cc;cxx;swift;s;S;asm;h;hpp;hxx;hh;inl";
const char* const browseableFileExtensions = "cpp;mm;m;metal;c;cc;cxx;swift;s;S;asm;h;hpp;hxx;hh;inl;txt;md;rtf";
const char* const fileTypesToCompileByDefault = "cpp;mm;m;metal;c;cc;cxx;swift;s;S;asm;r";
//==============================================================================
struct FileModificationDetector
{
FileModificationDetector (const File& f) : file (f) {}
const File& getFile() const { return file; }
void fileHasBeenRenamed (const File& newFile) { file = newFile; }
bool hasBeenModified() const
{
return fileModificationTime != file.getLastModificationTime()
&& (fileSize != file.getSize()
|| build_tools::calculateFileHashCode (file) != fileHashCode);
}
void updateHash()
{
fileModificationTime = file.getLastModificationTime();
fileSize = file.getSize();
fileHashCode = build_tools::calculateFileHashCode (file);
}
private:
File file;
Time fileModificationTime;
uint64 fileHashCode = 0;
int64 fileSize = -1;
};
@@ -0,0 +1,502 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "../../Application/jucer_Headers.h"
//==============================================================================
String joinLinesIntoSourceFile (StringArray& lines)
{
while (lines.size() > 10 && lines [lines.size() - 1].isEmpty())
lines.remove (lines.size() - 1);
return lines.joinIntoString (getPreferredLineFeed()) + getPreferredLineFeed();
}
String replaceLineFeeds (const String& content, const String& lineFeed)
{
StringArray lines;
lines.addLines (content);
return lines.joinIntoString (lineFeed);
}
String getLineFeedForFile (const String& fileContent)
{
auto t = fileContent.getCharPointer();
while (! t.isEmpty())
{
switch (t.getAndAdvance())
{
case 0: break;
case '\n': return "\n";
case '\r': if (*t == '\n') return "\r\n";
default: continue;
}
}
return {};
}
String trimCommentCharsFromStartOfLine (const String& line)
{
return line.trimStart().trimCharactersAtStart ("*/").trimStart();
}
String createAlphaNumericUID()
{
String uid;
const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random r;
uid << chars[r.nextInt (52)]; // make sure the first character is always a letter
for (int i = 5; --i >= 0;)
{
r.setSeedRandomly();
uid << chars [r.nextInt (62)];
}
return uid;
}
String createGUID (const String& seed)
{
auto hex = MD5 ((seed + "_guidsalt").toUTF8()).toHexString().toUpperCase();
return "{" + hex.substring (0, 8)
+ "-" + hex.substring (8, 12)
+ "-" + hex.substring (12, 16)
+ "-" + hex.substring (16, 20)
+ "-" + hex.substring (20, 32)
+ "}";
}
String escapeSpaces (const String& s)
{
return s.replace (" ", "\\ ");
}
String escapeQuotesAndSpaces (const String& s)
{
return escapeSpaces (s).replace ("'", "\\'").replace ("\"", "\\\"");
}
String addQuotesIfContainsSpaces (const String& text)
{
return (text.containsChar (' ') && ! text.isQuotedString()) ? text.quoted() : text;
}
void setValueIfVoid (Value value, const var& defaultValue)
{
if (value.getValue().isVoid())
value = defaultValue;
}
//==============================================================================
StringPairArray parsePreprocessorDefs (const String& text)
{
StringPairArray result;
auto s = text.getCharPointer();
while (! s.isEmpty())
{
String token, value;
s.incrementToEndOfWhitespace();
while ((! s.isEmpty()) && *s != '=' && ! s.isWhitespace())
token << s.getAndAdvance();
s.incrementToEndOfWhitespace();
if (*s == '=')
{
++s;
while ((! s.isEmpty()) && *s == ' ')
++s;
while ((! s.isEmpty()) && ! s.isWhitespace())
{
if (*s == ',')
{
++s;
break;
}
if (*s == '\\' && (s[1] == ' ' || s[1] == ','))
++s;
value << s.getAndAdvance();
}
}
if (token.isNotEmpty())
result.set (token, value);
}
return result;
}
StringPairArray mergePreprocessorDefs (StringPairArray inheritedDefs, const StringPairArray& overridingDefs)
{
for (int i = 0; i < overridingDefs.size(); ++i)
inheritedDefs.set (overridingDefs.getAllKeys()[i], overridingDefs.getAllValues()[i]);
return inheritedDefs;
}
String createGCCPreprocessorFlags (const StringPairArray& defs)
{
String s;
for (int i = 0; i < defs.size(); ++i)
{
auto def = defs.getAllKeys()[i];
auto value = defs.getAllValues()[i];
if (value.isNotEmpty())
def << "=" << value;
s += " \"" + ("-D" + def).replace ("\"", "\\\"") + "\"";
}
return s;
}
StringArray getSearchPathsFromString (const String& searchPath)
{
StringArray s;
s.addTokens (searchPath, ";\r\n", StringRef());
return getCleanedStringArray (s);
}
StringArray getCommaOrWhitespaceSeparatedItems (const String& sourceString)
{
StringArray s;
s.addTokens (sourceString, ", \t\r\n", StringRef());
return getCleanedStringArray (s);
}
StringArray getCleanedStringArray (StringArray s)
{
s.trim();
s.removeEmptyStrings();
return s;
}
//==============================================================================
void autoScrollForMouseEvent (const MouseEvent& e, bool scrollX, bool scrollY)
{
if (Viewport* const viewport = e.eventComponent->findParentComponentOfClass<Viewport>())
{
const MouseEvent e2 (e.getEventRelativeTo (viewport));
viewport->autoScroll (scrollX ? e2.x : 20, scrollY ? e2.y : 20, 8, 16);
}
}
//==============================================================================
int indexOfLineStartingWith (const StringArray& lines, const String& text, int index)
{
const int len = text.length();
for (const String* i = lines.begin() + index, * const e = lines.end(); i < e; ++i)
{
if (CharacterFunctions::compareUpTo (i->getCharPointer().findEndOfWhitespace(),
text.getCharPointer(), len) == 0)
return index;
++index;
}
return -1;
}
//==============================================================================
bool fileNeedsCppSyntaxHighlighting (const File& file)
{
if (file.hasFileExtension (sourceOrHeaderFileExtensions))
return true;
// This is a bit of a bodge to deal with libc++ headers with no extension..
char fileStart[128] = { 0 };
FileInputStream fin (file);
fin.read (fileStart, sizeof (fileStart) - 4);
return CharPointer_UTF8::isValidString (fileStart, sizeof (fileStart))
&& String (fileStart).trimStart().startsWith ("// -*- C++ -*-");
}
//==============================================================================
void writeAutoGenWarningComment (OutputStream& outStream)
{
outStream << "/*" << newLine << newLine
<< " IMPORTANT! This file is auto-generated each time you save your" << newLine
<< " project - if you alter its contents, your changes may be overwritten!" << newLine
<< newLine;
}
//==============================================================================
StringArray getJUCEModules() noexcept
{
static StringArray juceModuleIds =
{
"juce_analytics",
"juce_audio_basics",
"juce_audio_devices",
"juce_audio_formats",
"juce_audio_plugin_client",
"juce_audio_processors",
"juce_audio_utils",
"juce_box2d",
"juce_core",
"juce_cryptography",
"juce_data_structures",
"juce_dsp",
"juce_events",
"juce_graphics",
"juce_gui_basics",
"juce_gui_extra",
"juce_opengl",
"juce_osc",
"juce_product_unlocking",
"juce_video",
"juce_midi_ci"
};
return juceModuleIds;
}
bool isJUCEModule (const String& moduleID) noexcept
{
return getJUCEModules().contains (moduleID);
}
StringArray getModulesRequiredForConsole() noexcept
{
return
{
"juce_core",
"juce_data_structures",
"juce_events"
};
}
StringArray getModulesRequiredForComponent() noexcept
{
return
{
"juce_core",
"juce_data_structures",
"juce_events",
"juce_graphics",
"juce_gui_basics"
};
}
StringArray getModulesRequiredForAudioProcessor() noexcept
{
return
{
"juce_audio_basics",
"juce_audio_devices",
"juce_audio_formats",
"juce_audio_plugin_client",
"juce_audio_processors",
"juce_audio_utils",
"juce_core",
"juce_data_structures",
"juce_events",
"juce_graphics",
"juce_gui_basics",
"juce_gui_extra"
};
}
bool isPIPFile (const File& file) noexcept
{
for (auto line : StringArray::fromLines (file.loadFileAsString()))
{
auto trimmedLine = trimCommentCharsFromStartOfLine (line);
if (trimmedLine.startsWith ("BEGIN_JUCE_PIP_METADATA"))
return true;
}
return false;
}
bool isValidJUCEExamplesDirectory (const File& directory) noexcept
{
if (! directory.exists() || ! directory.isDirectory() || ! directory.containsSubDirectories())
return false;
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 bool isDivider (const String& line)
{
auto afterIndent = line.trim();
if (afterIndent.startsWith ("//") && afterIndent.length() > 20)
{
afterIndent = afterIndent.substring (5);
if (afterIndent.containsOnly ("=")
|| afterIndent.containsOnly ("/")
|| afterIndent.containsOnly ("-"))
{
return true;
}
}
return false;
}
static int getIndexOfCommentBlockStart (const StringArray& lines, int endIndex)
{
auto endLine = lines[endIndex];
if (endLine.contains ("*/"))
{
for (int i = endIndex; i >= 0; --i)
if (lines[i].contains ("/*"))
return i;
}
if (endLine.trim().startsWith ("//") && ! isDivider (endLine))
{
for (int i = endIndex; i >= 0; --i)
if (! lines[i].startsWith ("//") || isDivider (lines[i]))
return i + 1;
}
return -1;
}
int findBestLineToScrollToForClass (StringArray lines, const String& className, bool isPlugin)
{
for (auto line : lines)
{
if (line.contains ("struct " + className) || line.contains ("class " + className)
|| (isPlugin && line.contains ("public AudioProcessor") && ! line.contains ("AudioProcessorEditor")))
{
auto index = lines.indexOf (line);
auto commentBlockStartIndex = getIndexOfCommentBlockStart (lines, index - 1);
if (commentBlockStartIndex != -1)
index = commentBlockStartIndex;
if (isDivider (lines[index - 1]))
index -= 1;
return index;
}
}
return 0;
}
//==============================================================================
static var parseJUCEHeaderMetadata (const StringArray& lines)
{
auto* o = new DynamicObject();
var result (o);
for (auto& line : lines)
{
auto trimmedLine = trimCommentCharsFromStartOfLine (line);
auto colon = trimmedLine.indexOfChar (':');
if (colon >= 0)
{
auto key = trimmedLine.substring (0, colon).trim();
auto value = trimmedLine.substring (colon + 1).trim();
o->setProperty (key, value);
}
}
return result;
}
static String parseMetadataItem (const StringArray& lines, int& index)
{
String result = lines[index++];
while (index < lines.size())
{
auto continuationLine = trimCommentCharsFromStartOfLine (lines[index]);
if (continuationLine.isEmpty() || continuationLine.indexOfChar (':') != -1
|| continuationLine.startsWith ("END_JUCE_"))
break;
result += " " + continuationLine;
++index;
}
return result;
}
var parseJUCEHeaderMetadata (const File& file)
{
StringArray lines;
file.readLines (lines);
for (int i = 0; i < lines.size(); ++i)
{
auto trimmedLine = trimCommentCharsFromStartOfLine (lines[i]);
if (trimmedLine.startsWith ("BEGIN_JUCE_"))
{
StringArray desc;
auto j = i + 1;
while (j < lines.size())
{
if (trimCommentCharsFromStartOfLine (lines[j]).startsWith ("END_JUCE_"))
return parseJUCEHeaderMetadata (desc);
desc.add (parseMetadataItem (lines, j));
}
}
}
return {};
}
@@ -0,0 +1,138 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
const char* getPreferredLineFeed();
String joinLinesIntoSourceFile (StringArray& lines);
String replaceLineFeeds (const String& content, const String& lineFeed);
String getLineFeedForFile (const String& fileContent);
var parseJUCEHeaderMetadata (const File&);
String trimCommentCharsFromStartOfLine (const String& line);
String createAlphaNumericUID();
String createGUID (const String& seed); // Turns a seed into a windows GUID
String escapeSpaces (const String& text); // replaces spaces with blackslash-space
String escapeQuotesAndSpaces (const String& text);
String addQuotesIfContainsSpaces (const String& text);
StringPairArray parsePreprocessorDefs (const String& defs);
StringPairArray mergePreprocessorDefs (StringPairArray inheritedDefs, const StringPairArray& overridingDefs);
String createGCCPreprocessorFlags (const StringPairArray& defs);
StringArray getCleanedStringArray (StringArray);
StringArray getSearchPathsFromString (const String& searchPath);
StringArray getCommaOrWhitespaceSeparatedItems (const String&);
void setValueIfVoid (Value value, const var& defaultValue);
bool fileNeedsCppSyntaxHighlighting (const File& file);
void writeAutoGenWarningComment (OutputStream& outStream);
StringArray getJUCEModules() noexcept;
bool isJUCEModule (const String& moduleID) noexcept;
StringArray getModulesRequiredForConsole() noexcept;
StringArray getModulesRequiredForComponent() noexcept;
StringArray getModulesRequiredForAudioProcessor() noexcept;
bool isPIPFile (const File&) noexcept;
int findBestLineToScrollToForClass (StringArray, const String&, bool isPlugin = false);
bool isValidJUCEExamplesDirectory (const File&) noexcept;
bool isJUCEModulesFolder (const File&);
bool isJUCEFolder (const File&);
//==============================================================================
int indexOfLineStartingWith (const StringArray& lines, const String& text, int startIndex);
void autoScrollForMouseEvent (const MouseEvent& e, bool scrollX = true, bool scrollY = true);
//==============================================================================
struct PropertyListBuilder
{
void add (PropertyComponent* propertyComp)
{
components.add (propertyComp);
}
void add (PropertyComponent* propertyComp, const String& tooltip)
{
propertyComp->setTooltip (tooltip);
add (propertyComp);
}
void addSearchPathProperty (const Value& value,
const String& name,
const String& mainHelpText)
{
add (new TextPropertyComponent (value, name, 16384, true),
mainHelpText + " Use semi-colons or new-lines to separate multiple paths.");
}
void addSearchPathProperty (const ValueTreePropertyWithDefault& value,
const String& name,
const String& mainHelpText)
{
add (new TextPropertyComponent (value, name, 16384, true),
mainHelpText + " Use semi-colons or new-lines to separate multiple paths.");
}
void setPreferredHeight (int height)
{
for (int j = components.size(); --j >= 0;)
components.getUnchecked (j)->setPreferredHeight (height);
}
Array<PropertyComponent*> components;
};
//==============================================================================
// A ValueSource which takes an input source, and forwards any changes in it.
// This class is a handy way to create sources which re-map a value.
class ValueSourceFilter : public Value::ValueSource,
private Value::Listener
{
public:
ValueSourceFilter (const Value& source) : sourceValue (source)
{
sourceValue.addListener (this);
}
protected:
Value sourceValue;
private:
void valueChanged (Value&) override { sendChangeMessage (true); }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSourceFilter)
};
@@ -0,0 +1,296 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "../../Application/jucer_Headers.h"
#include "jucer_NewFileWizard.h"
//==============================================================================
namespace
{
static String fillInBasicTemplateFields (const File& file, const Project::Item& item, const char* templateName)
{
int dataSize;
if (auto* data = BinaryData::getNamedResource (templateName, dataSize))
{
auto fileTemplate = String::fromUTF8 (data, dataSize);
return replaceLineFeeds (fileTemplate.replace ("%%filename%%", file.getFileName(), false)
.replace ("%%date%%", Time::getCurrentTime().toString (true, true, true), false)
.replace ("%%author%%", SystemStats::getFullUserName(), false)
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (file.withFileExtension (".h"), file)),
item.project.getProjectLineFeed());
}
jassertfalse;
return {};
}
static bool fillInNewCppFileTemplate (const File& file, const Project::Item& item, const char* templateName)
{
return build_tools::overwriteFileWithNewDataIfDifferent (file, fillInBasicTemplateFields (file, item, templateName));
}
const int menuBaseID = 0x12d83f0;
}
//==============================================================================
class NewCppFileWizard final : public NewFileWizard::Type
{
public:
String getName() override { return "CPP File"; }
void createNewFile (Project&, Project::Item parent) override
{
askUserToChooseNewFile ("SourceCode.cpp", "*.cpp", parent, [this, parent] (File newFile)
{
if (newFile != File())
create (*this, parent, newFile, "jucer_NewCppFileTemplate_cpp");
});
}
static bool create (NewFileWizard::Type& wizard, Project::Item parent, const File& newFile, const char* templateName)
{
if (fillInNewCppFileTemplate (newFile, parent, templateName))
{
parent.addFileRetainingSortOrder (newFile, true);
return true;
}
wizard.showFailedToWriteMessage (newFile);
return false;
}
};
//==============================================================================
class NewHeaderFileWizard final : public NewFileWizard::Type
{
public:
String getName() override { return "Header File"; }
void createNewFile (Project&, Project::Item parent) override
{
askUserToChooseNewFile ("SourceCode.h", "*.h", parent, [this, parent] (File newFile)
{
if (newFile != File())
create (*this, parent, newFile, "jucer_NewCppFileTemplate_h");
});
}
static bool create (NewFileWizard::Type& wizard, Project::Item parent, const File& newFile, const char* templateName)
{
if (fillInNewCppFileTemplate (newFile, parent, templateName))
{
parent.addFileRetainingSortOrder (newFile, true);
return true;
}
wizard.showFailedToWriteMessage (newFile);
return false;
}
};
//==============================================================================
class NewCppAndHeaderFileWizard : public NewFileWizard::Type
{
public:
String getName() override { return "CPP & Header File"; }
void createNewFile (Project&, Project::Item parent) override
{
askUserToChooseNewFile ("SourceCode.h", "*.h;*.cpp", parent, [this, parent] (File newFile)
{
if (NewCppFileWizard::create (*this, parent, newFile.withFileExtension ("h"), "jucer_NewCppFileTemplate_h"))
NewCppFileWizard::create (*this, parent, newFile.withFileExtension ("cpp"), "jucer_NewCppFileTemplate_cpp");
});
}
};
//==============================================================================
class NewComponentFileWizard : public NewFileWizard::Type
{
public:
String getName() override { return "Component class (split between a CPP & header)"; }
void createNewFile (Project&, Project::Item parent) override
{
createNewFileInternal (parent);
}
static bool create (NewFileWizard::Type& wizard, const String& className, Project::Item parent,
const File& newFile, const char* templateName)
{
auto content = fillInBasicTemplateFields (newFile, parent, templateName)
.replace ("%%component_class%%", className)
.replace ("%%include_juce%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()));
content = replaceLineFeeds (content, parent.project.getProjectLineFeed());
if (build_tools::overwriteFileWithNewDataIfDifferent (newFile, content))
{
parent.addFileRetainingSortOrder (newFile, true);
return true;
}
wizard.showFailedToWriteMessage (newFile);
return false;
}
private:
virtual void createFiles (Project::Item parent, const String& className, const File& newFile)
{
if (create (*this, className, parent, newFile.withFileExtension ("h"), "jucer_NewComponentTemplate_h"))
create (*this, className, parent, newFile.withFileExtension ("cpp"), "jucer_NewComponentTemplate_cpp");
}
static String getClassNameFieldName() { return "Class Name"; }
void createNewFileInternal (Project::Item parent)
{
asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Create new Component class"),
TRANS ("Please enter the name for the new class"),
MessageBoxIconType::NoIcon, nullptr);
asyncAlertWindow->addTextEditor (getClassNameFieldName(), String(), String(), false);
asyncAlertWindow->addButton (TRANS ("Create Files"), 1, KeyPress (KeyPress::returnKey));
asyncAlertWindow->addButton (TRANS ("Cancel"), 0, KeyPress (KeyPress::escapeKey));
auto resultCallback = [safeThis = WeakReference<NewComponentFileWizard> { this }, parent] (int result)
{
if (safeThis == nullptr)
return;
auto& aw = *(safeThis->asyncAlertWindow);
aw.exitModalState (result);
aw.setVisible (false);
if (result == 0)
return;
const String className (aw.getTextEditorContents (getClassNameFieldName()).trim());
if (className == build_tools::makeValidIdentifier (className, false, true, false))
{
safeThis->askUserToChooseNewFile (className + ".h", "*.h;*.cpp",
parent,
[safeThis, parent, className] (File newFile)
{
if (safeThis == nullptr)
return;
if (newFile != File())
safeThis->createFiles (parent, className, newFile);
});
return;
}
safeThis->createNewFileInternal (parent);
};
asyncAlertWindow->enterModalState (true, ModalCallbackFunction::create (std::move (resultCallback)), false);
}
std::unique_ptr<AlertWindow> asyncAlertWindow;
JUCE_DECLARE_WEAK_REFERENCEABLE (NewComponentFileWizard)
};
//==============================================================================
class NewSingleFileComponentFileWizard final : public NewComponentFileWizard
{
public:
String getName() override { return "Component class (in a single source file)"; }
void createFiles (Project::Item parent, const String& className, const File& newFile) override
{
create (*this, className, parent, newFile.withFileExtension ("h"), "jucer_NewInlineComponentTemplate_h");
}
};
//==============================================================================
void NewFileWizard::Type::showFailedToWriteMessage (const File& file)
{
auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon,
"Failed to Create File!",
"Couldn't write to the file: " + file.getFullPathName());
messageBox = AlertWindow::showScopedAsync (options, nullptr);
}
void NewFileWizard::Type::askUserToChooseNewFile (const String& suggestedFilename, const String& wildcard,
const Project::Item& projectGroupToAddTo,
std::function<void (File)> callback)
{
chooser = std::make_unique<FileChooser> ("Select File to Create",
projectGroupToAddTo.determineGroupFolder()
.getChildFile (suggestedFilename)
.getNonexistentSibling(),
wildcard);
auto flags = FileBrowserComponent::saveMode
| FileBrowserComponent::canSelectFiles
| FileBrowserComponent::warnAboutOverwriting;
chooser->launchAsync (flags, [callback] (const FileChooser& fc)
{
callback (fc.getResult());
});
}
//==============================================================================
NewFileWizard::NewFileWizard()
{
registerWizard (new NewCppFileWizard());
registerWizard (new NewHeaderFileWizard());
registerWizard (new NewCppAndHeaderFileWizard());
registerWizard (new NewComponentFileWizard());
registerWizard (new NewSingleFileComponentFileWizard());
}
NewFileWizard::~NewFileWizard()
{
}
void NewFileWizard::addWizardsToMenu (PopupMenu& m) const
{
for (int i = 0; i < wizards.size(); ++i)
m.addItem (menuBaseID + i, "Add New " + wizards.getUnchecked (i)->getName() + "...");
}
bool NewFileWizard::runWizardFromMenu (int chosenMenuItemID, Project& project, const Project::Item& projectGroupToAddTo) const
{
if (Type* wiz = wizards [chosenMenuItemID - menuBaseID])
{
wiz->createNewFile (project, projectGroupToAddTo);
return true;
}
return false;
}
void NewFileWizard::registerWizard (Type* newWizard)
{
wizards.add (newWizard);
}
@@ -0,0 +1,70 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
#include "../../Project/jucer_Project.h"
//==============================================================================
class NewFileWizard
{
public:
//==============================================================================
NewFileWizard();
~NewFileWizard();
//==============================================================================
class Type
{
public:
virtual ~Type() = default;
//==============================================================================
virtual String getName() = 0;
virtual void createNewFile (Project&, Project::Item projectGroupToAddTo) = 0;
void showFailedToWriteMessage (const File& file);
protected:
//==============================================================================
void askUserToChooseNewFile (const String& suggestedFilename, const String& wildcard,
const Project::Item& projectGroupToAddTo,
std::function<void (File)> callback);
private:
std::unique_ptr<FileChooser> chooser;
ScopedMessageBox messageBox;
};
//==============================================================================
void addWizardsToMenu (PopupMenu&) const;
bool runWizardFromMenu (int chosenMenuItemID, Project&,
const Project::Item& projectGroupToAddTo) const;
void registerWizard (Type*);
private:
OwnedArray<Type> wizards;
};
@@ -0,0 +1,408 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
// Handy list of static Identifiers..
namespace Ids
{
#define DECLARE_ID(name) const Identifier name (#name)
DECLARE_ID (name);
DECLARE_ID (file);
DECLARE_ID (path);
DECLARE_ID (text);
DECLARE_ID (vendor);
DECLARE_ID (version);
DECLARE_ID (license);
DECLARE_ID (minimumCppStandard);
DECLARE_ID (include);
DECLARE_ID (info);
DECLARE_ID (description);
DECLARE_ID (companyName);
DECLARE_ID (companyCopyright);
DECLARE_ID (companyWebsite);
DECLARE_ID (companyEmail);
DECLARE_ID (useAppConfig);
DECLARE_ID (addUsingNamespaceToJuceHeader);
DECLARE_ID (usePrecompiledHeaderFile);
DECLARE_ID (precompiledHeaderFile);
DECLARE_ID (displaySplashScreen);
DECLARE_ID (splashScreenColour);
DECLARE_ID (position);
DECLARE_ID (source);
DECLARE_ID (width);
DECLARE_ID (height);
DECLARE_ID (bounds);
DECLARE_ID (background);
DECLARE_ID (initialState);
DECLARE_ID (targetFolder);
DECLARE_ID (intermediatesPath);
DECLARE_ID (modulePaths);
DECLARE_ID (searchpaths);
DECLARE_ID (osxFallback);
DECLARE_ID (windowsFallback);
DECLARE_ID (linuxFallback);
DECLARE_ID (jucePath);
DECLARE_ID (defaultJuceModulePath);
DECLARE_ID (defaultUserModulePath);
DECLARE_ID (vstLegacyFolder);
DECLARE_ID (vst3Folder);
DECLARE_ID (auFolder);
DECLARE_ID (vstLegacyPath);
DECLARE_ID (aaxPath);
DECLARE_ID (araPath);
DECLARE_ID (flags);
DECLARE_ID (line);
DECLARE_ID (index);
DECLARE_ID (type);
DECLARE_ID (time);
DECLARE_ID (extraCompilerFlags);
DECLARE_ID (extraLinkerFlags);
DECLARE_ID (externalLibraries);
DECLARE_ID (extraDefs);
DECLARE_ID (projectType);
DECLARE_ID (isDebug);
DECLARE_ID (alwaysGenerateDebugSymbols);
DECLARE_ID (targetName);
DECLARE_ID (binaryPath);
DECLARE_ID (recommendedWarnings);
DECLARE_ID (optimisation);
DECLARE_ID (defines);
DECLARE_ID (headerPath);
DECLARE_ID (systemHeaderPath);
DECLARE_ID (liveWindowsTargetPlatformVersion);
DECLARE_ID (libraryPath);
DECLARE_ID (customXcodeFlags);
DECLARE_ID (customXcassetsFolder);
DECLARE_ID (customLaunchStoryboard);
DECLARE_ID (customXcodeResourceFolders);
DECLARE_ID (plistPreprocessorDefinitions);
DECLARE_ID (applicationCategory);
DECLARE_ID (customPList);
DECLARE_ID (pListPrefixHeader);
DECLARE_ID (pListPreprocess);
DECLARE_ID (UIFileSharingEnabled);
DECLARE_ID (UISupportsDocumentBrowser);
DECLARE_ID (UIStatusBarHidden);
DECLARE_ID (UIRequiresFullScreen);
DECLARE_ID (documentExtensions);
DECLARE_ID (keepCustomXcodeSchemes);
DECLARE_ID (useHeaderMap);
DECLARE_ID (cppLanguageStandard);
DECLARE_ID (enableGNUExtensions);
DECLARE_ID (cppLibType);
DECLARE_ID (codeSigningIdentity);
DECLARE_ID (fastMath);
DECLARE_ID (linkTimeOptimisation);
DECLARE_ID (vstBinaryLocation);
DECLARE_ID (vst3BinaryLocation);
DECLARE_ID (auBinaryLocation);
DECLARE_ID (aaxBinaryLocation);
DECLARE_ID (unityPluginBinaryLocation);
DECLARE_ID (enablePluginBinaryCopyStep);
DECLARE_ID (stripLocalSymbols);
DECLARE_ID (macOSBaseSDK);
DECLARE_ID (macOSDeploymentTarget);
DECLARE_ID (osxArchitecture);
DECLARE_ID (iosBaseSDK);
DECLARE_ID (iosDeploymentTarget);
DECLARE_ID (xcodeSubprojects);
DECLARE_ID (extraFrameworks);
DECLARE_ID (frameworkSearchPaths);
DECLARE_ID (extraCustomFrameworks);
DECLARE_ID (embeddedFrameworks);
DECLARE_ID (extraDLLs);
DECLARE_ID (winArchitecture);
DECLARE_ID (winWarningLevel);
DECLARE_ID (msvcManifestFile);
DECLARE_ID (warningsAreErrors);
DECLARE_ID (linuxArchitecture);
DECLARE_ID (linuxCodeBlocksArchitecture);
DECLARE_ID (windowsCodeBlocksArchitecture);
DECLARE_ID (codeBlocksWindowsTarget);
DECLARE_ID (toolset);
DECLARE_ID (windowsTargetPlatformVersion);
DECLARE_ID (debugInformationFormat);
DECLARE_ID (IPPLibrary);
DECLARE_ID (IPP1ALibrary);
DECLARE_ID (MKL1ALibrary);
DECLARE_ID (msvcModuleDefinitionFile);
DECLARE_ID (bigIcon);
DECLARE_ID (smallIcon);
DECLARE_ID (prebuildCommand);
DECLARE_ID (postbuildCommand);
DECLARE_ID (generateManifest);
DECLARE_ID (useRuntimeLibDLL);
DECLARE_ID (multiProcessorCompilation);
DECLARE_ID (enableIncrementalLinking);
DECLARE_ID (bundleIdentifier);
DECLARE_ID (aaxIdentifier);
DECLARE_ID (araFactoryID);
DECLARE_ID (araDocumentArchiveID);
DECLARE_ID (araCompatibleArchiveIDs);
DECLARE_ID (aaxFolder);
DECLARE_ID (araFolder);
DECLARE_ID (compile);
DECLARE_ID (noWarnings);
DECLARE_ID (skipPCH);
DECLARE_ID (resource);
DECLARE_ID (xcodeResource);
DECLARE_ID (xcodeValidArchs);
DECLARE_ID (className);
DECLARE_ID (classDesc);
DECLARE_ID (controlPoint);
DECLARE_ID (createCallback);
DECLARE_ID (parentClasses);
DECLARE_ID (constructorParams);
DECLARE_ID (objectConstructionArgs);
DECLARE_ID (memberInitialisers);
DECLARE_ID (canBeAggregated);
DECLARE_ID (rootItemVisible);
DECLARE_ID (openByDefault);
DECLARE_ID (locked);
DECLARE_ID (tooltip);
DECLARE_ID (memberName);
DECLARE_ID (markerName);
DECLARE_ID (focusOrder);
DECLARE_ID (hidden);
DECLARE_ID (useStdCall);
DECLARE_ID (useGlobalPath);
DECLARE_ID (showAllCode);
DECLARE_ID (useLocalCopy);
DECLARE_ID (overwriteOnSave);
DECLARE_ID (appSandbox);
DECLARE_ID (appSandboxInheritance);
DECLARE_ID (appSandboxOptions);
DECLARE_ID (appSandboxHomeDirRO);
DECLARE_ID (appSandboxHomeDirRW);
DECLARE_ID (appSandboxAbsDirRO);
DECLARE_ID (appSandboxAbsDirRW);
DECLARE_ID (appSandboxExceptionIOKit);
DECLARE_ID (hardenedRuntime);
DECLARE_ID (hardenedRuntimeOptions);
DECLARE_ID (microphonePermissionNeeded);
DECLARE_ID (microphonePermissionsText);
DECLARE_ID (cameraPermissionNeeded);
DECLARE_ID (cameraPermissionText);
DECLARE_ID (sendAppleEventsPermissionNeeded);
DECLARE_ID (sendAppleEventsPermissionText);
DECLARE_ID (androidJavaLibs);
DECLARE_ID (androidAdditionalJavaFolders);
DECLARE_ID (androidAdditionalResourceFolders);
DECLARE_ID (androidProjectRepositories);
DECLARE_ID (androidRepositories);
DECLARE_ID (androidDependencies);
DECLARE_ID (androidCustomAppBuildGradleContent);
DECLARE_ID (androidBuildConfigRemoteNotifsConfigFile);
DECLARE_ID (androidAdditionalXmlValueResources);
DECLARE_ID (androidAdditionalDrawableResources);
DECLARE_ID (androidAdditionalRawValueResources);
// DECLARE_ID (androidActivityClass); // DEPRECATED!
const Identifier androidCustomActivityClass ("androidActivitySubClassName"); // old name is very confusing, but we need to remain backward compatible
// DECLARE_ID (androidActivityBaseClassName); // DEPRECATED!
DECLARE_ID (androidCustomApplicationClass);
DECLARE_ID (androidVersionCode);
DECLARE_ID (androidSDKPath);
DECLARE_ID (androidOboeRepositoryPath);
DECLARE_ID (androidInternetNeeded);
DECLARE_ID (androidArchitectures);
DECLARE_ID (androidManifestCustomXmlElements);
DECLARE_ID (androidGradleSettingsContent);
DECLARE_ID (androidCustomStringXmlElements);
DECLARE_ID (androidBluetoothNeeded);
DECLARE_ID (androidBluetoothScanNeeded);
DECLARE_ID (androidBluetoothAdvertiseNeeded);
DECLARE_ID (androidBluetoothConnectNeeded);
DECLARE_ID (androidExternalReadNeeded);
DECLARE_ID (androidReadMediaAudioPermission);
DECLARE_ID (androidReadMediaImagesPermission);
DECLARE_ID (androidReadMediaVideoPermission);
DECLARE_ID (androidExternalWriteNeeded);
DECLARE_ID (androidInAppBilling);
DECLARE_ID (androidVibratePermissionNeeded);
DECLARE_ID (androidPushNotifications);
DECLARE_ID (androidEnableRemoteNotifications);
DECLARE_ID (androidRemoteNotificationsConfigFile);
DECLARE_ID (androidEnableContentSharing);
DECLARE_ID (androidMinimumSDK);
DECLARE_ID (androidTargetSDK);
DECLARE_ID (androidOtherPermissions);
DECLARE_ID (androidKeyStore);
DECLARE_ID (androidKeyStorePass);
DECLARE_ID (androidKeyAlias);
DECLARE_ID (androidKeyAliasPass);
DECLARE_ID (androidTheme);
DECLARE_ID (androidStaticLibraries);
DECLARE_ID (androidSharedLibraries);
DECLARE_ID (androidScreenOrientation);
DECLARE_ID (androidExtraAssetsFolder);
DECLARE_ID (androidStudioExePath);
DECLARE_ID (iosDeviceFamily);
const Identifier iPhoneScreenOrientation ("iosScreenOrientation"); // old name is confusing
DECLARE_ID (iPadScreenOrientation);
DECLARE_ID (iosScreenOrientation);
DECLARE_ID (iosInAppPurchases);
DECLARE_ID (iosContentSharing);
DECLARE_ID (iosBackgroundAudio);
DECLARE_ID (iosBackgroundBle);
DECLARE_ID (iosPushNotifications);
DECLARE_ID (iosAppGroups);
DECLARE_ID (iCloudPermissions);
DECLARE_ID (networkingMulticast);
DECLARE_ID (iosDevelopmentTeamID);
DECLARE_ID (iosAppGroupsId);
DECLARE_ID (iosBluetoothPermissionNeeded);
DECLARE_ID (iosBluetoothPermissionText);
DECLARE_ID (duplicateAppExResourcesFolder);
DECLARE_ID (buildToolsVersion);
DECLARE_ID (gradleVersion);
const Identifier androidPluginVersion ("gradleWrapperVersion"); // old name is very confusing, but we need to remain backward compatible
DECLARE_ID (gradleToolchain);
DECLARE_ID (gradleToolchainVersion);
DECLARE_ID (gradleClangTidy);
DECLARE_ID (linuxExtraPkgConfig);
DECLARE_ID (font);
DECLARE_ID (colour);
DECLARE_ID (userNotes);
DECLARE_ID (maxBinaryFileSize);
DECLARE_ID (includeBinaryInJuceHeader);
DECLARE_ID (binaryDataNamespace);
DECLARE_ID (characterSet);
DECLARE_ID (JUCERPROJECT);
DECLARE_ID (MAINGROUP);
DECLARE_ID (EXPORTFORMATS);
DECLARE_ID (GROUP);
DECLARE_ID (FILE);
DECLARE_ID (MODULES);
DECLARE_ID (MODULE);
DECLARE_ID (JUCEOPTIONS);
DECLARE_ID (CONFIGURATIONS);
DECLARE_ID (CONFIGURATION);
DECLARE_ID (MODULEPATHS);
DECLARE_ID (MODULEPATH);
DECLARE_ID (PATH);
DECLARE_ID (userpath);
DECLARE_ID (systempath);
DECLARE_ID (utilsCppInclude);
DECLARE_ID (juceModulesFolder);
DECLARE_ID (parentActive);
DECLARE_ID (message);
DECLARE_ID (start);
DECLARE_ID (end);
DECLARE_ID (range);
DECLARE_ID (location);
DECLARE_ID (key);
DECLARE_ID (list);
DECLARE_ID (METADATA);
DECLARE_ID (DEPENDENCIES);
DECLARE_ID (CLASSLIST);
DECLARE_ID (CLASS);
DECLARE_ID (MEMBER);
DECLARE_ID (METHOD);
DECLARE_ID (LITERALS);
DECLARE_ID (LITERAL);
DECLARE_ID (abstract);
DECLARE_ID (anonymous);
DECLARE_ID (noDefConstructor);
DECLARE_ID (returnType);
DECLARE_ID (numArgs);
DECLARE_ID (declaration);
DECLARE_ID (definition);
DECLARE_ID (classDecl);
DECLARE_ID (initialisers);
DECLARE_ID (destructors);
DECLARE_ID (pluginFormats);
DECLARE_ID (buildVST);
DECLARE_ID (buildVST3);
DECLARE_ID (buildAU);
DECLARE_ID (buildAUv3);
DECLARE_ID (buildAAX);
DECLARE_ID (buildStandalone);
DECLARE_ID (buildUnity);
DECLARE_ID (buildLV2);
DECLARE_ID (enableIAA);
DECLARE_ID (enableARA);
DECLARE_ID (pluginName);
DECLARE_ID (pluginDesc);
DECLARE_ID (pluginManufacturer);
DECLARE_ID (pluginManufacturerCode);
DECLARE_ID (pluginCode);
DECLARE_ID (pluginChannelConfigs);
DECLARE_ID (pluginCharacteristicsValue);
DECLARE_ID (pluginCharacteristics);
DECLARE_ID (extraPluginFormats);
DECLARE_ID (pluginIsSynth);
DECLARE_ID (pluginWantsMidiIn);
DECLARE_ID (pluginProducesMidiOut);
DECLARE_ID (pluginIsMidiEffectPlugin);
DECLARE_ID (pluginEditorRequiresKeys);
DECLARE_ID (pluginVSTCategory);
DECLARE_ID (pluginVST3Category);
DECLARE_ID (pluginAUExportPrefix);
DECLARE_ID (pluginAUMainType);
DECLARE_ID (pluginAUIsSandboxSafe);
DECLARE_ID (pluginAAXCategory);
DECLARE_ID (pluginAAXDisableBypass);
DECLARE_ID (pluginAAXDisableMultiMono);
DECLARE_ID (pluginARAAnalyzableContent);
DECLARE_ID (pluginARATransformFlags);
DECLARE_ID (pluginVSTNumMidiInputs);
DECLARE_ID (pluginVSTNumMidiOutputs);
DECLARE_ID (suppressPlistResourceUsage);
DECLARE_ID (useLegacyBuildSystem);
DECLARE_ID (exporters);
DECLARE_ID (website);
DECLARE_ID (mainClass);
DECLARE_ID (documentControllerClass);
DECLARE_ID (moduleFlags);
DECLARE_ID (projectLineFeed);
DECLARE_ID (compilerFlagSchemes);
DECLARE_ID (compilerFlagScheme);
DECLARE_ID (dontQueryForUpdate);
DECLARE_ID (dontAskAboutJUCEPath);
DECLARE_ID (postExportShellCommandPosix);
DECLARE_ID (postExportShellCommandWin);
DECLARE_ID (guiEditorEnabled);
DECLARE_ID (jucerFormatVersion);
DECLARE_ID (buildNumber);
DECLARE_ID (lv2Uri);
DECLARE_ID (lv2UriUi);
DECLARE_ID (lv2BinaryLocation);
DECLARE_ID (vst3ManifestEnabled);
DECLARE_ID (osxSDK);
DECLARE_ID (osxCompatibility);
DECLARE_ID (iosCompatibility);
const Identifier ID ("id");
const Identifier ID_uppercase ("ID");
const Identifier class_ ("class");
const Identifier dependencies_ ("dependencies");
#undef DECLARE_ID
}
@@ -0,0 +1,324 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
struct TranslationHelpers
{
static void addString (StringArray& strings, const String& s)
{
if (s.isNotEmpty() && ! strings.contains (s))
strings.add (s);
}
static void scanFileForTranslations (StringArray& strings, const File& file)
{
auto content = file.loadFileAsString();
auto p = content.getCharPointer();
for (;;)
{
p = CharacterFunctions::find (p, CharPointer_ASCII ("TRANS"));
if (p.isEmpty())
break;
p += 5;
p.incrementToEndOfWhitespace();
if (*p == '(')
{
++p;
MemoryOutputStream text;
parseStringLiteral (p, text);
addString (strings, text.toString());
}
}
}
static void parseStringLiteral (String::CharPointerType& p, MemoryOutputStream& out) noexcept
{
p.incrementToEndOfWhitespace();
if (p.getAndAdvance() == '"')
{
auto start = p;
for (;;)
{
auto c = *p;
if (c == '"')
{
out << String (start, p);
++p;
parseStringLiteral (p, out);
return;
}
if (c == 0)
break;
if (c == '\\')
{
out << String (start, p);
++p;
out << String::charToString (readEscapedChar (p));
start = p + 1;
}
++p;
}
}
}
static juce_wchar readEscapedChar (String::CharPointerType& p)
{
auto c = *p;
switch (c)
{
case '"':
case '\\':
case '/': break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'x':
++p;
c = 0;
for (int i = 4; --i >= 0;)
{
const int digitValue = CharacterFunctions::getHexDigitValue (*p);
if (digitValue < 0)
break;
++p;
c = (c << 4) + (juce_wchar) digitValue;
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
c = 0;
for (int i = 4; --i >= 0;)
{
const auto digitValue = (int) (*p - '0');
if (digitValue < 0 || digitValue > 7)
break;
++p;
c = (c << 3) + (juce_wchar) digitValue;
}
break;
default:
break;
}
return c;
}
static void scanFilesForTranslations (StringArray& strings, const Project::Item& p)
{
if (p.isFile())
{
const File file (p.getFile());
if (file.hasFileExtension (sourceOrHeaderFileExtensions))
scanFileForTranslations (strings, file);
}
for (int i = 0; i < p.getNumChildren(); ++i)
scanFilesForTranslations (strings, p.getChild (i));
}
static void scanFolderForTranslations (StringArray& strings, const File& root)
{
for (const auto& i : RangedDirectoryIterator (root, true))
{
const auto file = i.getFile();
if (file.hasFileExtension (sourceOrHeaderFileExtensions))
scanFileForTranslations (strings, file);
}
}
static void scanProject (StringArray& strings, Project& project)
{
scanFilesForTranslations (strings, project.getMainGroup());
OwnedArray<LibraryModule> modules;
project.getEnabledModules().createRequiredModules (modules);
for (int j = 0; j < modules.size(); ++j)
{
const File localFolder (modules.getUnchecked (j)->getFolder());
Array<File> files;
modules.getUnchecked (j)->findBrowseableFiles (localFolder, files);
for (int i = 0; i < files.size(); ++i)
scanFileForTranslations (strings, files.getReference (i));
}
}
static const char* getMungingSeparator() { return "JCTRIDX"; }
static StringArray breakApart (const String& munged)
{
StringArray lines, result;
lines.addLines (munged);
String currentItem;
for (int i = 0; i < lines.size(); ++i)
{
if (lines[i].contains (getMungingSeparator()))
{
if (currentItem.isNotEmpty())
result.add (currentItem);
currentItem = String();
}
else
{
if (currentItem.isNotEmpty())
currentItem << newLine;
currentItem << lines[i];
}
}
if (currentItem.isNotEmpty())
result.add (currentItem);
return result;
}
static StringArray withTrimmedEnds (StringArray array)
{
for (auto& s : array)
s = s.trimEnd().removeCharacters ("\r\n");
return array;
}
static String escapeString (const String& s)
{
return s.replace ("\"", "\\\"")
.replace ("\'", "\\\'")
.replace ("\t", "\\t")
.replace ("\r", "\\r")
.replace ("\n", "\\n");
}
static String getPreTranslationText (Project& project)
{
StringArray strings;
scanProject (strings, project);
return mungeStrings (strings);
}
static String getPreTranslationText (const LocalisedStrings& strings)
{
return mungeStrings (strings.getMappings().getAllKeys());
}
static String mungeStrings (const StringArray& strings)
{
MemoryOutputStream s;
for (int i = 0; i < strings.size(); ++i)
{
s << getMungingSeparator() << i << "." << newLine << strings[i];
if (i < strings.size() - 1)
s << newLine;
}
return s.toString();
}
static String createLine (const String& preString, const String& postString)
{
return "\"" + escapeString (preString)
+ "\" = \""
+ escapeString (postString) + "\"";
}
static String createFinishedTranslationFile (StringArray preStrings,
StringArray postStrings,
const LocalisedStrings& original)
{
const StringPairArray& originalStrings (original.getMappings());
StringArray lines;
if (originalStrings.size() > 0)
{
lines.add ("language: " + original.getLanguageName());
lines.add ("countries: " + original.getCountryCodes().joinIntoString (" "));
lines.add (String());
const StringArray& originalKeys (originalStrings.getAllKeys());
const StringArray& originalValues (originalStrings.getAllValues());
for (int i = preStrings.size(); --i >= 0;)
{
if (originalKeys.contains (preStrings[i]))
{
preStrings.remove (i);
postStrings.remove (i);
}
}
for (int i = 0; i < originalStrings.size(); ++i)
lines.add (createLine (originalKeys[i], originalValues[i]));
}
else
{
lines.add ("language: [enter full name of the language here!]");
lines.add ("countries: [enter list of 2-character country codes here!]");
lines.add (String());
}
for (int i = 0; i < preStrings.size(); ++i)
lines.add (createLine (preStrings[i], postStrings[i]));
return lines.joinIntoString (newLine);
}
};
@@ -0,0 +1,50 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
template <typename Type>
class NumericValueSource final : public ValueSourceFilter
{
public:
NumericValueSource (const Value& source) : ValueSourceFilter (source) {}
var getValue() const override
{
return (Type) sourceValue.getValue();
}
void setValue (const var& newValue) override
{
const Type newVal = static_cast<Type> (newValue);
if (newVal != static_cast<Type> (getValue())) // this test is important, because if a property is missing, it won't
sourceValue = newVal; // create it (causing an unwanted undo action) when a control sets it to 0
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NumericValueSource)
};
@@ -0,0 +1,75 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
/**
Wraps a ValueTreePropertyWithDefault object that has a default which depends on a global value.
*/
class ValueTreePropertyWithDefaultWrapper final : private Value::Listener
{
public:
ValueTreePropertyWithDefaultWrapper() = default;
void init (const ValueTreePropertyWithDefault& v,
ValueTreePropertyWithDefault global,
TargetOS::OS targetOS)
{
wrappedValue = v;
globalValue = global.getPropertyAsValue();
globalIdentifier = global.getPropertyID();
os = targetOS;
if (wrappedValue.get() == var())
wrappedValue.resetToDefault();
globalValue.addListener (this);
valueChanged (globalValue);
}
ValueTreePropertyWithDefault& getWrappedValueTreePropertyWithDefault()
{
return wrappedValue;
}
var getCurrentValue() const
{
return wrappedValue.get();
}
private:
void valueChanged (Value&) override
{
wrappedValue.setDefault (getAppSettings().getStoredPath (globalIdentifier, os).get());
}
ValueTreePropertyWithDefault wrappedValue;
Value globalValue;
Identifier globalIdentifier;
TargetOS::OS os;
};
@@ -0,0 +1,126 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "../../Application/jucer_Headers.h"
#include "jucer_VersionInfo.h"
VersionInfo::VersionInfo (String versionIn, String releaseNotesIn, std::vector<Asset> assetsIn)
: versionString (std::move (versionIn)),
releaseNotes (std::move (releaseNotesIn)),
assets (std::move (assetsIn))
{}
std::unique_ptr<VersionInfo> VersionInfo::fetchFromUpdateServer (const String& versionString)
{
return fetch ("tags/" + versionString);
}
std::unique_ptr<VersionInfo> VersionInfo::fetchLatestFromUpdateServer()
{
return fetch ("latest");
}
std::unique_ptr<InputStream> VersionInfo::createInputStreamForAsset (const Asset& asset, int& statusCode)
{
URL downloadUrl (asset.url);
StringPairArray responseHeaders;
return std::unique_ptr<InputStream> (downloadUrl.createInputStream (URL::InputStreamOptions (URL::ParameterHandling::inAddress)
.withExtraHeaders ("Accept: application/octet-stream")
.withConnectionTimeoutMs (5000)
.withResponseHeaders (&responseHeaders)
.withStatusCode (&statusCode)
.withNumRedirectsToFollow (1)));
}
bool VersionInfo::isNewerVersionThanCurrent()
{
jassert (versionString.isNotEmpty());
auto currentTokens = StringArray::fromTokens (ProjectInfo::versionString, ".", {});
auto thisTokens = StringArray::fromTokens (versionString, ".", {});
jassert (thisTokens.size() == 3);
if (currentTokens[0].getIntValue() == thisTokens[0].getIntValue())
{
if (currentTokens[1].getIntValue() == thisTokens[1].getIntValue())
return currentTokens[2].getIntValue() < thisTokens[2].getIntValue();
return currentTokens[1].getIntValue() < thisTokens[1].getIntValue();
}
return currentTokens[0].getIntValue() < thisTokens[0].getIntValue();
}
std::unique_ptr<VersionInfo> VersionInfo::fetch (const String& endpoint)
{
URL latestVersionURL ("https://api.github.com/repos/juce-framework/JUCE/releases/" + endpoint);
std::unique_ptr<InputStream> inStream (latestVersionURL.createInputStream (URL::InputStreamOptions (URL::ParameterHandling::inAddress)
.withConnectionTimeoutMs (5000)));
if (inStream == nullptr)
return nullptr;
auto content = inStream->readEntireStreamAsString();
auto latestReleaseDetails = JSON::parse (content);
auto* json = latestReleaseDetails.getDynamicObject();
if (json == nullptr)
return nullptr;
auto versionString = json->getProperty ("tag_name").toString();
if (versionString.isEmpty())
return nullptr;
auto* assets = json->getProperty ("assets").getArray();
if (assets == nullptr)
return nullptr;
auto releaseNotes = json->getProperty ("body").toString();
std::vector<VersionInfo::Asset> parsedAssets;
for (auto& asset : *assets)
{
if (auto* assetJson = asset.getDynamicObject())
{
parsedAssets.push_back ({ assetJson->getProperty ("name").toString(),
assetJson->getProperty ("url").toString() });
jassert (parsedAssets.back().name.isNotEmpty());
jassert (parsedAssets.back().url.isNotEmpty());
}
else
{
jassertfalse;
}
}
return std::unique_ptr<VersionInfo> (new VersionInfo { versionString, releaseNotes, std::move (parsedAssets) });
}
@@ -0,0 +1,53 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
class VersionInfo
{
public:
struct Asset
{
const String name;
const String url;
};
static std::unique_ptr<VersionInfo> fetchFromUpdateServer (const String& versionString);
static std::unique_ptr<VersionInfo> fetchLatestFromUpdateServer();
static std::unique_ptr<InputStream> createInputStreamForAsset (const Asset& asset, int& statusCode);
bool isNewerVersionThanCurrent();
const String versionString;
const String releaseNotes;
const std::vector<Asset> assets;
private:
VersionInfo (String version, String releaseNotes, std::vector<Asset> assets);
static std::unique_ptr<VersionInfo> fetch (const String&);
};