author | mseledtsov |
Wed, 17 May 2017 11:28:56 -0700 | |
changeset 46220 | c9a98ebe678b |
parent 23010 | 6dadb192ad81 |
permissions | -rw-r--r-- |
3742 | 1 |
/* |
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
21805
diff
changeset
|
2 |
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. |
3742 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
3742 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
3742 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
3742 | 24 |
*/ |
25 |
package build.tools.generatenimbus; |
|
26 |
||
27 |
import java.io.*; |
|
28 |
import java.util.HashMap; |
|
29 |
import java.util.Map; |
|
30 |
import javax.xml.bind.JAXBContext; |
|
31 |
import javax.xml.bind.Unmarshaller; |
|
32 |
||
33 |
/** |
|
34 |
* Generates the various Java artifacts based on a SynthModel. |
|
35 |
* <p/> |
|
36 |
* Generated source files are split up among two different locations. There are those source files that are meant to be |
|
37 |
* edited (generally, only the LookAndFeel class itself) and those that are autogenerated (everything else). |
|
38 |
* <p/> |
|
39 |
* All autogenerated files are placed in "buildPackageRoot" and are package private. A LAF author (one who has access to |
|
40 |
* the generated sources) will be able to access any of the generated classes. Those referencing the library, however, |
|
41 |
* will only be able to access the main LookAndFeel class itself (since everything else is package private). |
|
42 |
* |
|
43 |
* @author Richard Bair |
|
44 |
* @author Jasper Potts |
|
45 |
*/ |
|
46 |
public class Generator { |
|
47 |
private static Generator instance; |
|
48 |
||
49 |
/** A map of variables that are used for variable substitution in the template files. */ |
|
50 |
private Map<String, String> variables; |
|
51 |
private boolean full = false; |
|
52 |
private File buildPackageRoot; |
|
53 |
private String packageNamePrefix; |
|
54 |
private String lafName; |
|
55 |
private SynthModel model; |
|
56 |
||
57 |
/** |
|
58 |
* MAIN APPLICATION |
|
59 |
* <p/> |
|
60 |
* This is for using the generator as part of the java build process |
|
61 |
* |
|
62 |
* @param args The commandline arguments |
|
63 |
*/ |
|
64 |
public static void main(String[] args) throws Exception { |
|
65 |
if (args.length == 0 || (args.length % 2) != 0) { |
|
66 |
System.out.println("Usage: generator [-options]\n" + |
|
67 |
" -full <true|false> True if we should build the whole LAF or false for building just states and painters.\n" + |
|
68 |
" -skinFile <value> Path to the skin.laf file for the LAF to be generated from.\n" + |
|
69 |
" -buildDir <value> The directory beneath which the build-controlled artifacts (such as the Painters) should\n" + |
|
70 |
" be placed. This is the root directory beneath which the necessary packages and source\n" + |
|
71 |
" files will be created.\n" + |
|
72 |
" -resourcesDir <value> The resources directory containing templates and images.\n" + |
|
73 |
" -packagePrefix <value> The package name associated with this synth look and feel. For example,\n" + |
|
74 |
" \"org.mypackage.mylaf\"\n" + |
|
75 |
" -lafName <value> The name of the laf, such as \"MyLAF\".\n"); |
|
76 |
} else { |
|
77 |
boolean full = false; |
|
78 |
File skinFile = new File(System.getProperty("user.dir")); |
|
79 |
File buildDir = new File(System.getProperty("user.dir")); |
|
80 |
File resourcesDir = new File(System.getProperty("user.dir")); |
|
81 |
String packagePrefix = "org.mypackage.mylaf"; |
|
82 |
String lafName = "MyLAF"; |
|
83 |
for (int i = 0; i < args.length; i += 2) { |
|
84 |
String key = args[i].trim().toLowerCase(); |
|
85 |
String value = args[i + 1].trim(); |
|
86 |
if ("-full".equals(key)) { |
|
87 |
full = Boolean.parseBoolean(value); |
|
88 |
} else if ("-skinfile".equals(key)) { |
|
89 |
skinFile = new File(value); |
|
90 |
} else if ("-builddir".equals(key)) { |
|
91 |
buildDir = new File(value); |
|
92 |
} else if ("-resourcesdir".equals(key)) { |
|
93 |
resourcesDir = new File(value); |
|
94 |
} else if ("-packageprefix".equals(key)) { |
|
95 |
packagePrefix = value; |
|
96 |
} else if ("-lafname".equals(key)) { |
|
97 |
lafName = value; |
|
98 |
} |
|
99 |
} |
|
100 |
System.out.println("### GENERATING LAF CODE ################################"); |
|
101 |
System.out.println(" full :" + full); |
|
102 |
System.out.println(" skinFile :" + skinFile.getAbsolutePath()); |
|
103 |
System.out.println(" buildDir :" + buildDir.getAbsolutePath()); |
|
104 |
System.out.println(" resourcesDir :" + resourcesDir.getAbsolutePath()); |
|
105 |
System.out.println(" packagePrefix :" +packagePrefix); |
|
106 |
System.out.println(" lafName :" +lafName); |
|
107 |
||
108 |
JAXBContext ctx = JAXBContext.newInstance("build.tools.generatenimbus"); |
|
109 |
Unmarshaller u = ctx.createUnmarshaller(); |
|
110 |
SynthModel model = (SynthModel) u.unmarshal(skinFile); |
|
111 |
Generator.init(full, buildDir, packagePrefix, lafName, model); |
|
112 |
Generator.getInstance().generate(); |
|
113 |
} |
|
114 |
} |
|
115 |
||
116 |
/** |
|
117 |
* Creates a new Generator, capable of outputting the source code artifacts related to a given SynthModel. It is |
|
118 |
* capable of generating the one-time artifacts in addition to the regeneration of build-controlled artifacts. |
|
119 |
* |
|
120 |
* @param full True if we should build the whole LAF or false for building just states and painters. |
|
121 |
* @param buildDir The directory beneath which the build-controlled artifacts (such as the Painters) should |
|
122 |
* be placed. This is the root directory beneath which the necessary packages and source |
|
123 |
* files will be created. |
|
124 |
* @param srcDir The directory beneath which the normal user-controlled artifacts (such as the core |
|
125 |
* LookAndFeel file) should be placed. These are one-time generated files. This is the root |
|
126 |
* directory beneath which the necessary packages and source files will be created. |
|
127 |
* @param packageNamePrefix The package name associated with this synth look and feel. For example, |
|
128 |
* org.mypackage.mylaf |
|
129 |
* @param lafName The name of the laf, such as MyLAF. |
|
130 |
* @param model The actual SynthModel to base these generated files on. |
|
131 |
*/ |
|
132 |
private Generator(boolean full, File buildDir, |
|
133 |
String packageNamePrefix, String lafName, SynthModel model) { |
|
134 |
this.full = full; |
|
135 |
//validate the input variables |
|
136 |
if (packageNamePrefix == null) { |
|
137 |
throw new IllegalArgumentException("You must specify a package name prefix"); |
|
138 |
} |
|
139 |
if (buildDir == null) { |
|
140 |
throw new IllegalArgumentException("You must specify the build directory"); |
|
141 |
} |
|
142 |
if (model == null) { |
|
143 |
throw new IllegalArgumentException("You must specify the SynthModel"); |
|
144 |
} |
|
145 |
if (lafName == null) { |
|
146 |
throw new IllegalArgumentException("You must specify the name of the look and feel"); |
|
147 |
} |
|
148 |
||
149 |
//construct the map which is used to do variable substitution of the template |
|
150 |
//files |
|
151 |
variables = new HashMap<String, String>(); |
|
152 |
variables.put("PACKAGE", packageNamePrefix); |
|
153 |
variables.put("LAF_NAME", lafName); |
|
154 |
||
155 |
//generate and save references to the package-root directories. |
|
156 |
//(That is, given the buildDir and srcDir, generate references to the |
|
157 |
//org.mypackage.mylaf subdirectories) |
|
158 |
buildPackageRoot = new File(buildDir, packageNamePrefix.replaceAll("\\.", "\\/")); |
|
159 |
buildPackageRoot.mkdirs(); |
|
160 |
||
161 |
//save the variables |
|
162 |
this.packageNamePrefix = packageNamePrefix; |
|
163 |
this.lafName = lafName; |
|
164 |
this.model = model; |
|
165 |
} |
|
166 |
||
167 |
public static void init(boolean full, File buildDir, |
|
168 |
String packageNamePrefix, String lafName, SynthModel model) { |
|
169 |
instance = new Generator(full, buildDir, packageNamePrefix, lafName, model); |
|
170 |
model.initStyles(); |
|
171 |
} |
|
172 |
||
173 |
public static Generator getInstance() { |
|
174 |
return instance; |
|
175 |
} |
|
176 |
||
177 |
public static Map<String, String> getVariables() { |
|
178 |
return new HashMap<String, String>(instance.variables); |
|
179 |
} |
|
180 |
||
181 |
public void generate() { |
|
182 |
if (full) { |
|
183 |
//create the LookAndFeel file |
|
184 |
writeSrcFileImpl("LookAndFeel", variables, lafName + "LookAndFeel"); |
|
185 |
||
186 |
writeSrcFileImpl("AbstractRegionPainter", variables); |
|
187 |
writeSrcFileImpl("BlendingMode", variables); |
|
188 |
writeSrcFileImpl("SynthPainterImpl", variables); |
|
189 |
writeSrcFileImpl("IconImpl", variables, lafName + "Icon.java"); |
|
190 |
writeSrcFileImpl("StyleImpl", variables, lafName + "Style.java"); |
|
191 |
writeSrcFileImpl("Effect", variables); |
|
192 |
writeSrcFileImpl("EffectUtils", variables); |
|
193 |
writeSrcFileImpl("ShadowEffect", variables); |
|
194 |
writeSrcFileImpl("DropShadowEffect", variables); |
|
195 |
writeSrcFileImpl("InnerShadowEffect", variables); |
|
196 |
writeSrcFileImpl("InnerGlowEffect", variables); |
|
197 |
writeSrcFileImpl("OuterGlowEffect", variables); |
|
198 |
writeSrcFileImpl("State", variables); |
|
199 |
writeSrcFileImpl("ImageCache", variables); |
|
200 |
writeSrcFileImpl("ImageScalingHelper", variables); |
|
201 |
} |
|
202 |
//next, populate the first set of ui defaults based on what is in the |
|
203 |
//various palettes of the synth model |
|
204 |
StringBuilder defBuffer = new StringBuilder(); |
|
205 |
StringBuilder styleBuffer = new StringBuilder(); |
|
206 |
model.write(defBuffer, styleBuffer, packageNamePrefix); |
|
207 |
||
208 |
Map<String, String> vars = getVariables(); |
|
209 |
vars.put("UI_DEFAULT_INIT", defBuffer.toString()); |
|
210 |
vars.put("STYLE_INIT", styleBuffer.toString()); |
|
211 |
writeSrcFile("Defaults", vars, lafName + "Defaults"); |
|
212 |
} |
|
213 |
||
214 |
private void writeSrcFileImpl(String name, Map<String, String> variables) { |
|
215 |
writeSrcFileImpl(name, variables, name); |
|
216 |
} |
|
217 |
||
218 |
private void writeSrcFileImpl(String templateName, |
|
219 |
Map<String, String> variables, String outputName) { |
|
220 |
PrintWriter out = null; |
|
221 |
try { |
|
222 |
InputStream stream = getClass().getResourceAsStream( |
|
223 |
"resources/" + templateName + ".template"); |
|
224 |
TemplateReader in = new TemplateReader(variables, stream); |
|
225 |
||
226 |
out = new PrintWriter(new File(buildPackageRoot, outputName + ".java")); |
|
227 |
String line = in.readLine(); |
|
228 |
while (line != null) { |
|
229 |
out.println(line); |
|
230 |
line = in.readLine(); |
|
231 |
} |
|
232 |
} catch (IOException e) { |
|
233 |
throw new RuntimeException("IOException in writer", e); |
|
234 |
} finally { |
|
235 |
if (out != null) out.close(); |
|
236 |
} |
|
237 |
} |
|
238 |
||
239 |
public static void writeSrcFile(String templateName, |
|
240 |
Map<String, String> variables, String outputName) { |
|
241 |
instance.writeSrcFileImpl(templateName, variables, outputName); |
|
242 |
} |
|
243 |
||
244 |
/** A BufferedReader implementation that automatically performs |
|
245 |
* string replacements as needed. |
|
246 |
*/ |
|
247 |
private static final class TemplateReader extends BufferedReader { |
|
248 |
private Map<String, String> variables; |
|
249 |
||
250 |
TemplateReader(Map<String, String> variables, InputStream template) { |
|
251 |
super(new InputStreamReader(template)); |
|
252 |
this.variables = variables; |
|
253 |
} |
|
254 |
||
255 |
@Override public String readLine() throws IOException { |
|
256 |
return substituteVariables(super.readLine()); |
|
257 |
} |
|
258 |
||
259 |
private String substituteVariables(String input) { |
|
260 |
if (input == null) return null; |
|
261 |
for (Map.Entry<String, String> variable : variables.entrySet()) { |
|
262 |
input = input.replace("${" + variable.getKey() + "}", variable.getValue()); |
|
263 |
} |
|
264 |
return input; |
|
265 |
} |
|
266 |
} |
|
267 |
} |