1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-18 00:54:19 +00:00
JUCE/extras/the jucer/src/model/jucer_GeneratedCode.cpp
2010-04-23 09:37:13 +01:00

382 lines
12 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.
==============================================================================
*/
#include "../jucer_Headers.h"
#include "jucer_GeneratedCode.h"
//==============================================================================
GeneratedCode::GeneratedCode (const JucerDocument* const document_)
: document (document_),
suffix (0)
{
}
GeneratedCode::~GeneratedCode()
{
}
int GeneratedCode::getUniqueSuffix()
{
return ++suffix;
}
//==============================================================================
String& GeneratedCode::getCallbackCode (const String& requiredParentClass,
const String& returnType,
const String& prototype,
const bool hasPrePostUserSections)
{
String parentClass (requiredParentClass);
if (parentClass.isNotEmpty()
&& ! (parentClass.startsWith (T("public "))
|| parentClass.startsWith (T("private "))
|| parentClass.startsWith (T("protected "))))
{
parentClass = T("public ") + parentClass;
}
for (int i = callbacks.size(); --i >= 0;)
{
CallbackMethod* const cm = callbacks.getUnchecked(i);
if (cm->requiredParentClass == parentClass
&& cm->returnType == returnType
&& cm->prototype == prototype)
return cm->content;
}
CallbackMethod* const cm = new CallbackMethod();
callbacks.add (cm);
cm->requiredParentClass = parentClass;
cm->returnType = returnType;
cm->prototype = prototype;
cm->hasPrePostUserSections = hasPrePostUserSections;
return cm->content;
}
void GeneratedCode::removeCallback (const String& returnType, const String& prototype)
{
for (int i = callbacks.size(); --i >= 0;)
{
CallbackMethod* const cm = callbacks.getUnchecked(i);
if (cm->returnType == returnType && cm->prototype == prototype)
callbacks.remove (i);
}
}
void GeneratedCode::addImageResourceLoader (const String& imageMemberName, const String& resourceName)
{
const String initialiser (imageMemberName + T(" (0)"));
if (! initialisers.contains (initialiser, false))
{
initialisers.add (initialiser);
privateMemberDeclarations
<< "Image* " << imageMemberName << ";\n";
if (resourceName.isNotEmpty())
{
constructorCode
<< imageMemberName << " = ImageCache::getFromMemory ("
<< resourceName << ", " << resourceName << "Size);\n";
destructorCode
<< "ImageCache::release (" << imageMemberName << ");\n";
}
}
}
const StringArray GeneratedCode::getExtraParentClasses() const
{
StringArray s;
for (int i = 0; i < callbacks.size(); ++i)
{
CallbackMethod* const cm = callbacks.getUnchecked(i);
s.add (cm->requiredParentClass);
}
return s;
}
const String GeneratedCode::getCallbackDeclarations() const
{
String s;
for (int i = 0; i < callbacks.size(); ++i)
{
CallbackMethod* const cm = callbacks.getUnchecked(i);
s << cm->returnType << " " << cm->prototype << ";\n";
}
return s;
}
const String GeneratedCode::getCallbackDefinitions() const
{
String s;
for (int i = 0; i < callbacks.size(); ++i)
{
CallbackMethod* const cm = callbacks.getUnchecked(i);
const String userCodeBlockName (T("User")
+ makeValidCppIdentifier (cm->prototype.upToFirstOccurrenceOf (T("("), false, false),
true, true, false).trim());
if (userCodeBlockName.isNotEmpty() && cm->hasPrePostUserSections)
{
s << cm->returnType << " " << className << "::" << cm->prototype
<< "\n{\n //[" << userCodeBlockName << "_Pre]\n //[/" << userCodeBlockName
<< "_Pre]\n\n "
<< indentCode (cm->content.trim(), 4)
<< "\n\n //[" << userCodeBlockName << "_Post]\n //[/" << userCodeBlockName
<< "_Post]\n}\n\n";
}
else
{
s << cm->returnType << " " << className << "::" << cm->prototype
<< "\n{\n "
<< indentCode (cm->content.trim(), 4)
<< "\n}\n\n";
}
}
return s;
}
//==============================================================================
const String GeneratedCode::getClassDeclaration() const
{
StringArray parentClassLines;
parentClassLines.addTokens (parentClasses, T(","), String::empty);
parentClassLines.addArray (getExtraParentClasses());
parentClassLines.trim();
parentClassLines.removeEmptyStrings();
parentClassLines.removeDuplicates (false);
if (parentClassLines.contains (T("public Button"), false))
parentClassLines.removeString (("public Component"), false);
String r (T("class "));
r << className << T(" : ");
r += parentClassLines.joinIntoString (T(",\n") + String::repeatedString (T(" "), r.length()));
return r;
}
const String GeneratedCode::getInitialiserList() const
{
StringArray inits (initialisers);
if (parentClassInitialiser.isNotEmpty())
inits.insert (0, parentClassInitialiser);
inits.trim();
inits.removeEmptyStrings();
inits.removeDuplicates (false);
String s;
if (inits.size() == 0)
return s;
s << " : ";
for (int i = 0; i < inits.size(); ++i)
{
String init (inits[i]);
while (init.endsWithChar (T(',')))
init = init.dropLastCharacters (1);
s << init;
if (i < inits.size() - 1)
s << ",\n ";
else
s << "\n";
}
return s;
}
static const String getIncludeFileCode (StringArray files)
{
files.trim();
files.removeEmptyStrings();
files.removeDuplicates (false);
String s;
for (int i = 0; i < files.size(); ++i)
s << T("#include \"") << files[i] << T("\"\n");
return s;
}
//==============================================================================
static void replaceTemplate (String& text, const String& itemName, const String& value)
{
for (;;)
{
const int index = text.indexOf (T("%%") + itemName + T("%%"));
if (index < 0)
break;
int indentLevel = 0;
for (int i = index; --i >= 0;)
{
if (text[i] == T('\n'))
break;
++indentLevel;
}
text = text.replaceSection (index, itemName.length() + 4,
indentCode (value, indentLevel));
}
}
//==============================================================================
static bool getUserSection (const StringArray& lines, const String& tag, StringArray& resultLines)
{
const int start = indexOfLineStartingWith (lines, T("//[") + tag + T("]"), 0);
if (start < 0)
return false;
const int end = indexOfLineStartingWith (lines, T("//[/") + tag + T("]"), start + 1);
for (int i = start + 1; i < end; ++i)
resultLines.add (lines [i]);
return true;
}
static void copyAcrossUserSections (String& dest, const String& src)
{
StringArray srcLines, dstLines;
srcLines.addLines (src);
dstLines.addLines (dest);
for (int i = 0; i < dstLines.size(); ++i)
{
if (dstLines[i].trimStart().startsWith (T("//[")))
{
String tag (dstLines[i].trimStart().substring (3));
tag = tag.upToFirstOccurrenceOf (T("]"), false, false);
jassert (! tag.startsWithChar (T('/')));
if (! tag.startsWithChar (T('/')))
{
const int endLine = indexOfLineStartingWith (dstLines,
T("//[/") + tag + T("]"),
i + 1);
if (endLine > i)
{
StringArray sourceLines;
if (getUserSection (srcLines, tag, sourceLines))
{
int j;
for (j = endLine - i; --j > 0;)
dstLines.remove (i + 1);
for (j = 0; j < sourceLines.size(); ++j)
dstLines.insert (++i, sourceLines [j].trimEnd());
++i;
}
else
{
i = endLine;
}
}
}
}
dstLines.set (i, dstLines[i].trimEnd());
}
dest = dstLines.joinIntoString (T("\n")) + T("\n");
}
//==============================================================================
void GeneratedCode::applyToCode (String& code,
const String& fileNameRoot,
const bool isForPreview,
const String& oldFileWithUserData) const
{
// header guard..
String headerGuard ("__JUCER_HEADER_");
headerGuard << className.toUpperCase().retainCharacters (T("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
<< "_" << fileNameRoot.toUpperCase().retainCharacters (T("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
<< "_" << String::toHexString (Random::getSystemRandom().nextInt()).toUpperCase()
<< "__";
replaceTemplate (code, "headerGuard", headerGuard);
replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true));
replaceTemplate (code, "className", className);
replaceTemplate (code, "constructorParams", constructorParams);
replaceTemplate (code, "initialisers", getInitialiserList());
replaceTemplate (code, "classDeclaration", getClassDeclaration());
replaceTemplate (code, "privateMemberDeclarations", privateMemberDeclarations);
replaceTemplate (code, "publicMemberDeclarations", getCallbackDeclarations() + "\n" + publicMemberDeclarations);
replaceTemplate (code, "methodDefinitions", getCallbackDefinitions());
replaceTemplate (code, "includeFilesH", getIncludeFileCode (includeFilesH));
replaceTemplate (code, "includeFilesCPP", getIncludeFileCode (includeFilesCPP));
replaceTemplate (code, "constructor", constructorCode);
replaceTemplate (code, "destructor", destructorCode);
if (! isForPreview)
{
replaceTemplate (code, "metadata", jucerMetadata);
replaceTemplate (code, "staticMemberDefinitions", staticMemberDefinitions);
}
else
{
replaceTemplate (code, "metadata", T(" << Metadata isn't shown in the code preview >>\n"));
replaceTemplate (code, "staticMemberDefinitions", T("// Static member declarations and resources would go here... (these aren't shown in the code preview)"));
}
copyAcrossUserSections (code, oldFileWithUserData);
}