The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../jucer_Headers.h"
  18. #include "jucer_GeneratedCode.h"
  19. #include "jucer_JucerDocument.h"
  20. //==============================================================================
  21. GeneratedCode::GeneratedCode (const JucerDocument* const doc)
  22. : document (doc), suffix (0)
  23. {
  24. }
  25. GeneratedCode::~GeneratedCode()
  26. {
  27. }
  28. int GeneratedCode::getUniqueSuffix()
  29. {
  30. return ++suffix;
  31. }
  32. //==============================================================================
  33. String& GeneratedCode::getCallbackCode (const String& requiredParentClass,
  34. const String& returnType,
  35. const String& prototype,
  36. const bool hasPrePostUserSections)
  37. {
  38. String parentClass (requiredParentClass);
  39. if (parentClass.isNotEmpty()
  40. && ! (parentClass.startsWith ("public ")
  41. || parentClass.startsWith ("private ")
  42. || parentClass.startsWith ("protected ")))
  43. {
  44. parentClass = "public " + parentClass;
  45. }
  46. for (int i = callbacks.size(); --i >= 0;)
  47. {
  48. CallbackMethod* const cm = callbacks.getUnchecked(i);
  49. if (cm->requiredParentClass == parentClass
  50. && cm->returnType == returnType
  51. && cm->prototype == prototype)
  52. return cm->content;
  53. }
  54. CallbackMethod* const cm = new CallbackMethod();
  55. callbacks.add (cm);
  56. cm->requiredParentClass = parentClass;
  57. cm->returnType = returnType;
  58. cm->prototype = prototype;
  59. cm->hasPrePostUserSections = hasPrePostUserSections;
  60. return cm->content;
  61. }
  62. void GeneratedCode::removeCallback (const String& returnType, const String& prototype)
  63. {
  64. for (int i = callbacks.size(); --i >= 0;)
  65. {
  66. CallbackMethod* const cm = callbacks.getUnchecked(i);
  67. if (cm->returnType == returnType && cm->prototype == prototype)
  68. callbacks.remove (i);
  69. }
  70. }
  71. void GeneratedCode::addImageResourceLoader (const String& imageMemberName, const String& resourceName)
  72. {
  73. privateMemberDeclarations
  74. << "Image " << imageMemberName << ";\n";
  75. if (resourceName.isNotEmpty())
  76. constructorCode << imageMemberName << " = ImageCache::getFromMemory ("
  77. << resourceName << ", " << resourceName << "Size);\n";
  78. }
  79. StringArray GeneratedCode::getExtraParentClasses() const
  80. {
  81. StringArray s;
  82. for (int i = 0; i < callbacks.size(); ++i)
  83. {
  84. CallbackMethod* const cm = callbacks.getUnchecked(i);
  85. s.add (cm->requiredParentClass);
  86. }
  87. return s;
  88. }
  89. String GeneratedCode::getCallbackDeclarations() const
  90. {
  91. String s;
  92. for (int i = 0; i < callbacks.size(); ++i)
  93. {
  94. CallbackMethod* const cm = callbacks.getUnchecked(i);
  95. s << cm->returnType << " " << cm->prototype << ";\n";
  96. }
  97. return s;
  98. }
  99. String GeneratedCode::getCallbackDefinitions() const
  100. {
  101. String s;
  102. for (int i = 0; i < callbacks.size(); ++i)
  103. {
  104. CallbackMethod* const cm = callbacks.getUnchecked(i);
  105. const String userCodeBlockName ("User"
  106. + CodeHelpers::makeValidIdentifier (cm->prototype.upToFirstOccurrenceOf ("(", false, false),
  107. true, true, false).trim());
  108. if (userCodeBlockName.isNotEmpty() && cm->hasPrePostUserSections)
  109. {
  110. s << cm->returnType << " " << className << "::" << cm->prototype
  111. << "\n{\n //[" << userCodeBlockName << "_Pre]\n //[/" << userCodeBlockName
  112. << "_Pre]\n\n "
  113. << CodeHelpers::indent (cm->content.trim(), 4, false)
  114. << "\n\n //[" << userCodeBlockName << "_Post]\n //[/" << userCodeBlockName
  115. << "_Post]\n}\n\n";
  116. }
  117. else
  118. {
  119. s << cm->returnType << " " << className << "::" << cm->prototype
  120. << "\n{\n "
  121. << CodeHelpers::indent (cm->content.trim(), 4, false)
  122. << "\n}\n\n";
  123. }
  124. }
  125. return s;
  126. }
  127. //==============================================================================
  128. String GeneratedCode::getClassDeclaration() const
  129. {
  130. StringArray parentClassLines;
  131. parentClassLines.addTokens (parentClasses, ",", String::empty);
  132. parentClassLines.addArray (getExtraParentClasses());
  133. parentClassLines.trim();
  134. parentClassLines.removeEmptyStrings();
  135. parentClassLines.removeDuplicates (false);
  136. if (parentClassLines.contains ("public Button", false))
  137. parentClassLines.removeString ("public Component", false);
  138. String r ("class ");
  139. r << className << " : ";
  140. r += parentClassLines.joinIntoString (",\n" + String::repeatedString (" ", r.length()));
  141. return r;
  142. }
  143. String GeneratedCode::getInitialiserList() const
  144. {
  145. StringArray inits (initialisers);
  146. if (parentClassInitialiser.isNotEmpty())
  147. inits.insert (0, parentClassInitialiser);
  148. inits.trim();
  149. inits.removeEmptyStrings();
  150. inits.removeDuplicates (false);
  151. String s;
  152. if (inits.size() == 0)
  153. return s;
  154. s << " : ";
  155. for (int i = 0; i < inits.size(); ++i)
  156. {
  157. String init (inits[i]);
  158. while (init.endsWithChar (','))
  159. init = init.dropLastCharacters (1);
  160. s << init;
  161. if (i < inits.size() - 1)
  162. s << ",\n ";
  163. else
  164. s << "\n";
  165. }
  166. return s;
  167. }
  168. static String getIncludeFileCode (StringArray files)
  169. {
  170. files.trim();
  171. files.removeEmptyStrings();
  172. files.removeDuplicates (false);
  173. String s;
  174. for (int i = 0; i < files.size(); ++i)
  175. s << "#include \"" << files[i] << "\"\n";
  176. return s;
  177. }
  178. bool GeneratedCode::shouldUseTransMacro() const noexcept
  179. {
  180. return document->shouldUseTransMacro();
  181. }
  182. //==============================================================================
  183. static void replaceTemplate (String& text, const String& itemName, const String& value)
  184. {
  185. for (;;)
  186. {
  187. const int index = text.indexOf ("%%" + itemName + "%%");
  188. if (index < 0)
  189. break;
  190. int indentLevel = 0;
  191. for (int i = index; --i >= 0;)
  192. {
  193. if (text[i] == '\n')
  194. break;
  195. ++indentLevel;
  196. }
  197. text = text.replaceSection (index, itemName.length() + 4,
  198. CodeHelpers::indent (value, indentLevel, false));
  199. }
  200. }
  201. //==============================================================================
  202. static bool getUserSection (const StringArray& lines, const String& tag, StringArray& resultLines)
  203. {
  204. const int start = indexOfLineStartingWith (lines, "//[" + tag + "]", 0);
  205. if (start < 0)
  206. return false;
  207. const int end = indexOfLineStartingWith (lines, "//[/" + tag + "]", start + 1);
  208. for (int i = start + 1; i < end; ++i)
  209. resultLines.add (lines [i]);
  210. return true;
  211. }
  212. static void copyAcrossUserSections (String& dest, const String& src)
  213. {
  214. StringArray srcLines, dstLines;
  215. srcLines.addLines (src);
  216. dstLines.addLines (dest);
  217. for (int i = 0; i < dstLines.size(); ++i)
  218. {
  219. if (dstLines[i].trimStart().startsWith ("//["))
  220. {
  221. String tag (dstLines[i].trimStart().substring (3));
  222. tag = tag.upToFirstOccurrenceOf ("]", false, false);
  223. jassert (! tag.startsWithChar ('/'));
  224. if (! tag.startsWithChar ('/'))
  225. {
  226. const int endLine = indexOfLineStartingWith (dstLines,
  227. "//[/" + tag + "]",
  228. i + 1);
  229. if (endLine > i)
  230. {
  231. StringArray sourceLines;
  232. if (getUserSection (srcLines, tag, sourceLines))
  233. {
  234. for (int j = endLine - i; --j > 0;)
  235. dstLines.remove (i + 1);
  236. for (int j = 0; j < sourceLines.size(); ++j)
  237. dstLines.insert (++i, sourceLines [j].trimEnd());
  238. ++i;
  239. }
  240. else
  241. {
  242. i = endLine;
  243. }
  244. }
  245. }
  246. }
  247. dstLines.set (i, dstLines[i].trimEnd());
  248. }
  249. dest = dstLines.joinIntoString ("\n") + "\n";
  250. }
  251. //==============================================================================
  252. void GeneratedCode::applyToCode (String& code,
  253. const String& fileNameRoot,
  254. const bool isForPreview,
  255. const String& oldFileWithUserData) const
  256. {
  257. // header guard..
  258. String headerGuard ("__JUCE_HEADER_");
  259. headerGuard << String::toHexString ((className + "xx" + fileNameRoot).hashCode64()).toUpperCase() << "__";
  260. replaceTemplate (code, "headerGuard", headerGuard);
  261. replaceTemplate (code, "version", JUCEApplicationBase::getInstance()->getApplicationVersion());
  262. replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true));
  263. replaceTemplate (code, "className", className);
  264. replaceTemplate (code, "constructorParams", constructorParams);
  265. replaceTemplate (code, "initialisers", getInitialiserList());
  266. replaceTemplate (code, "classDeclaration", getClassDeclaration());
  267. replaceTemplate (code, "privateMemberDeclarations", privateMemberDeclarations);
  268. replaceTemplate (code, "publicMemberDeclarations", getCallbackDeclarations() + "\n" + publicMemberDeclarations);
  269. replaceTemplate (code, "methodDefinitions", getCallbackDefinitions());
  270. replaceTemplate (code, "includeFilesH", getIncludeFileCode (includeFilesH));
  271. replaceTemplate (code, "includeFilesCPP", getIncludeFileCode (includeFilesCPP));
  272. replaceTemplate (code, "constructor", constructorCode);
  273. replaceTemplate (code, "destructor", destructorCode);
  274. if (! isForPreview)
  275. {
  276. replaceTemplate (code, "metadata", jucerMetadata);
  277. replaceTemplate (code, "staticMemberDefinitions", staticMemberDefinitions);
  278. }
  279. else
  280. {
  281. replaceTemplate (code, "metadata", " << Metadata isn't shown in the code preview >>\n");
  282. replaceTemplate (code, "staticMemberDefinitions", "// Static member declarations and resources would go here... (these aren't shown in the code preview)");
  283. }
  284. copyAcrossUserSections (code, oldFileWithUserData);
  285. }