/AppKit/Themes/CommonJS/blendtask.j

http://github.com/aparajita/cappuccino · Unknown · 258 lines · 194 code · 64 blank · 0 comment · 0 complexity · a30bdf54ca9c5bf7265b87e5506a9165 MD5 · raw file

  1. /*
  2. * blendtask.j
  3. * BlendKit
  4. *
  5. * Created by Francisco Tolmasky.
  6. * Copyright 2009, 280 North, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. @import <Foundation/CPObject.j>
  23. @import <Foundation/CPData.j>
  24. @import <Foundation/CPKeyedArchiver.j>
  25. @import <AppKit/CPCib.j>
  26. @import <AppKit/_CPCibObjectData.j>
  27. @import <BlendKit/BlendKit.j>
  28. var FILE = require("file"),
  29. TERM = require("narwhal/term"),
  30. task = require("jake").task,
  31. filedir = require("jake").filedir,
  32. BundleTask = require("objective-j/jake/bundletask").BundleTask;
  33. function BlendTask(aName)
  34. {
  35. BundleTask.apply(this, arguments);
  36. this._themeDescriptors = [];
  37. this._keyedThemes = [];
  38. }
  39. BlendTask.__proto__ = BundleTask;
  40. BlendTask.prototype.__proto__ = BundleTask.prototype;
  41. BlendTask.prototype.packageType = function()
  42. {
  43. return "BLND";
  44. };
  45. BlendTask.prototype.infoPlist = function()
  46. {
  47. var infoPlist = BundleTask.prototype.infoPlist.apply(this, arguments);
  48. infoPlist.setValueForKey("CPKeyedThemes", require("narwhal/util").unique(this._keyedThemes));
  49. return infoPlist;
  50. };
  51. BlendTask.prototype.themeDescriptors = function()
  52. {
  53. return this._themeDescriptors;
  54. };
  55. BlendTask.prototype.setThemeDescriptors = function(/*Array | FileList*/ themeDescriptors)
  56. {
  57. this._themeDescriptors = themeDescriptors;
  58. };
  59. BlendTask.prototype.defineTasks = function()
  60. {
  61. this.defineThemeDescriptorTasks();
  62. BundleTask.prototype.defineTasks.apply(this, arguments);
  63. };
  64. BlendTask.prototype.defineSourceTasks = function()
  65. {
  66. };
  67. BlendTask.prototype.defineThemeDescriptorTasks = function()
  68. {
  69. this.environments().forEach(function(anEnvironment)
  70. {
  71. var folder = anEnvironment.name() + ".environment",
  72. themeDescriptors = this.themeDescriptors(),
  73. resourcesPath = this.resourcesPath(),
  74. intermediatesPath = FILE.join(this.buildIntermediatesProductPath(), folder, "Resources"),
  75. staticPath = this.buildProductStaticPathForEnvironment(anEnvironment),
  76. keyedThemes = this._keyedThemes,
  77. themesTaskName = this.name() + ":themes";
  78. this.enhance(themesTaskName);
  79. themeDescriptors.forEach(function(/*CPString*/ themeDescriptorPath)
  80. {
  81. objj_importFile(FILE.absolute(themeDescriptorPath), YES);
  82. });
  83. [BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
  84. {
  85. var keyedThemePath = FILE.join(intermediatesPath, [aClass themeName] + ".keyedtheme");
  86. filedir (keyedThemePath, themesTaskName);
  87. filedir (staticPath, [keyedThemePath]);
  88. keyedThemes.push([aClass themeName] + ".keyedtheme");
  89. });
  90. task (themesTaskName, function()
  91. {
  92. [BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
  93. {
  94. var themeTemplate = [[BKThemeTemplate alloc] init];
  95. [themeTemplate setValue:[aClass themeName] forKey:@"name"];
  96. var objectTemplates = [aClass themedObjectTemplates],
  97. data = cibDataFromTopLevelObjects(objectTemplates.concat([themeTemplate])),
  98. fileContents = themeFromCibData(data);
  99. // No filedir in this case, so we have to make it ourselves.
  100. FILE.mkdirs(intermediatesPath);
  101. // FIXME: MARKER_TEXT isn't global, so we use "t;".
  102. FILE.write(FILE.join(intermediatesPath, [aClass themeName] + ".keyedtheme"), "t;" + fileContents.length + ";" + fileContents, { charset:"UTF-8" });
  103. });
  104. });
  105. }, this);
  106. };
  107. function cibDataFromTopLevelObjects(objects)
  108. {
  109. var data = [CPData data],
  110. archiver = [[CPKeyedArchiver alloc] initForWritingWithMutableData:data],
  111. objectData = [[_CPCibObjectData alloc] init];
  112. objectData._fileOwner = [_CPCibCustomObject new];
  113. objectData._fileOwner._className = @"CPObject";
  114. var index = 0,
  115. count = objects.length;
  116. for (; index < count; ++index)
  117. {
  118. objectData._objectsValues[index] = objectData._fileOwner;
  119. objectData._objectsKeys[index] = objects[index];
  120. }
  121. [archiver encodeObject:objectData forKey:@"CPCibObjectDataKey"];
  122. [archiver finishEncoding];
  123. return data;
  124. }
  125. function themeFromCibData(data)
  126. {
  127. var cib = [[CPCib alloc] initWithData:data],
  128. topLevelObjects = [];
  129. [cib _setAwakenCustomResources:NO];
  130. [cib instantiateCibWithExternalNameTable:[CPDictionary dictionaryWithObject:topLevelObjects forKey:CPCibTopLevelObjects]];
  131. var count = topLevelObjects.length,
  132. theme = nil,
  133. templates = [];
  134. while (count--)
  135. {
  136. var object = topLevelObjects[count];
  137. templates = templates.concat([object blendThemeObjectTemplates]);
  138. if ([object isKindOfClass:[BKThemeTemplate class]])
  139. theme = [[CPTheme alloc] initWithName:[object valueForKey:@"name"]];
  140. }
  141. TERM.stream.print("Building \0green(" + [theme name] + "\0) theme");
  142. [templates makeObjectsPerformSelector:@selector(blendAddThemedObjectAttributesToTheme:) withObject:theme];
  143. return [[CPKeyedArchiver archivedDataWithRootObject:theme] rawString];
  144. }
  145. @implementation CPCib (BlendAdditions)
  146. - (id)initWithData:(CPData)aData
  147. {
  148. self = [super init];
  149. if (self)
  150. _data = aData;
  151. return self;
  152. }
  153. @end
  154. @implementation CPObject (BlendAdditions)
  155. - (CPArray)blendThemeObjectTemplates
  156. {
  157. var theClass = [self class];
  158. if ([theClass isKindOfClass:[BKThemedObjectTemplate class]])
  159. return [self];
  160. if ([theClass isKindOfClass:[CPView class]])
  161. {
  162. var templates = [],
  163. subviews = [self subviews],
  164. count = [subviews count];
  165. while (count--)
  166. templates = templates.concat([subviews[count] blendThemeObjectTemplates]);
  167. return templates;
  168. }
  169. return [];
  170. }
  171. @end
  172. @implementation BKThemedObjectTemplate (BlendAdditions)
  173. - (void)blendAddThemedObjectAttributesToTheme:(CPTheme)aTheme
  174. {
  175. var themedObject = [self valueForKey:@"themedObject"];
  176. if (!themedObject)
  177. {
  178. var subviews = [self subviews];
  179. if ([subviews count] > 0)
  180. themedObject = subviews[0];
  181. }
  182. if (themedObject)
  183. {
  184. TERM.stream.print(" Recording themed properties for \0purple(" + [themedObject className] + "\0).");
  185. [aTheme takeThemeFromObject:themedObject];
  186. }
  187. }
  188. @end
  189. exports.BlendTask = BlendTask;
  190. exports.blend = function(aName, aFunction)
  191. {
  192. // No .apply necessary because the parameters aren't variable.
  193. return BlendTask.defineTask(aName, aFunction);
  194. };