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.

366 lines
11KB

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