blob: 6ab4b87d18ad38d9f28eb5895ed16b9be4478094 [file] [log] [blame]
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.synthdesigner.generator;
import static org.jdesktop.synthdesigner.generator.TemplateWriter.read;
import static org.jdesktop.synthdesigner.generator.TemplateWriter.writeSrcFile;
import org.jdesktop.synthdesigner.synthmodel.SynthModel;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IUnmarshallingContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Generates the various Java artifacts based on a SynthModel.
* <p/>
* Generated source files are split up among two different locations. There are those source files that are meant to be
* edited (generally, only the LookAndFeel class itself) and those that are autogenerated (everything else).
* <p/>
* All autogenerated files are placed in "buildPackageRoot" and are package private. A LAF author (one who has access to
* the generated sources) will be able to access any of the generated classes. Those referencing the library, however,
* will only be able to access the main LookAndFeel class itself (since everything else is package private).
*
* @author Richard Bair
* @author Jasper Potts
*/
public class Generator {
/** A map of variables that are used for variable substitution in the template files. */
private Map<String, String> variables;
private boolean full = false;
private File buildPackageRoot;
private File srcPackageRoot;
private String packageNamePrefix;
private String lafName;
private SynthModel model;
/**
* MAIN APPLICATION
* <p/>
* This is for using the generator as part of the java build process
*
* @param args The commandline arguments
*/
public static void main(String[] args) {
if (args.length == 0 || (args.length % 2) != 0) {
System.out.println("Usage: generator [-options]\n" +
" -full <true|false> True if we should build the whole LAF or false for building just states and painters.\n" +
" -skinFile <value> Path to the skin.laf file for the LAF to be generated from.\n" +
" -buildDir <value> The directory beneath which the build-controlled artifacts (such as the Painters) should\n" +
" be placed. This is the root directory beneath which the necessary packages and source\n" +
" files will be created.\n" +
" -srcDir <value> The directory beneath which the normal user-controlled artifacts (such as the core\n" +
" LookAndFeel file) should be placed. These are one-time generated files. This is the root\n" +
" directory beneath which the necessary packages and source files will be created.\n" +
" -resourcesDir <value> The resources directory containing templates and images.\n" +
" -packagePrefix <value> The package name associated with this synth look and feel. For example,\n" +
" \"org.mypackage.mylaf\"\n" +
" -lafName <value> The name of the laf, such as \"MyLAF\".\n");
} else {
boolean full = false;
File skinFile = new File(System.getProperty("user.dir"));
File buildDir = new File(System.getProperty("user.dir"));
File srcDir = new File(System.getProperty("user.dir"));
File resourcesDir = new File(System.getProperty("user.dir"));
String packagePrefix = "org.mypackage.mylaf";
String lafName = "MyLAF";
for (int i = 0; i < args.length; i += 2) {
String key = args[i].trim().toLowerCase();
String value = args[i + 1].trim();
if ("-full".equals(key)) {
full = Boolean.parseBoolean(value);
} else if ("-skinfile".equals(key)) {
skinFile = new File(value);
} else if ("-builddir".equals(key)) {
buildDir = new File(value);
} else if ("-srcdir".equals(key)) {
srcDir = new File(value);
} else if ("-resourcesdir".equals(key)) {
resourcesDir = new File(value);
} else if ("-packageprefix".equals(key)) {
packagePrefix = value;
} else if ("-lafname".equals(key)) {
lafName = value;
}
}
System.out.println("### GENERATING LAF CODE ################################");
System.out.println(" full :" + full);
System.out.println(" skinFile :" + skinFile.getAbsolutePath());
System.out.println(" buildDir :" + buildDir.getAbsolutePath());
System.out.println(" srcDir :" + srcDir.getAbsolutePath());
System.out.println(" resourcesDir :" + resourcesDir.getAbsolutePath());
System.out.println(" packagePrefix :" +packagePrefix);
System.out.println(" lafName :" +lafName);
try {
// LOAD SKIN MODEL
IBindingFactory bindingFactory = BindingDirectory.getFactory(SynthModel.class);
IUnmarshallingContext mctx = bindingFactory.createUnmarshallingContext();
mctx.setDocument(new FileInputStream(skinFile), "UTF-8");
// pass resources directory in as user context so it can be used in SynthModel preSet
mctx.setUserContext(resourcesDir);
SynthModel model = (SynthModel) mctx.unmarshalElement();
// create and run generator
Generator generator = new Generator(full, buildDir, srcDir, packagePrefix, lafName, model);
generator.generate();
} catch (Exception e) {
System.err.println("Error loading skin and generating java src:");
e.printStackTrace();
}
}
}
/**
* Creates a new Generator, capable of outputting the source code artifacts related to a given SynthModel. It is
* capable of generating the one-time artifacts in addition to the regeneration of build-controlled artifacts.
*
* @param full True if we should build the whole LAF or false for building just states and painters.
* @param buildDir The directory beneath which the build-controlled artifacts (such as the Painters) should
* be placed. This is the root directory beneath which the necessary packages and source
* files will be created.
* @param srcDir The directory beneath which the normal user-controlled artifacts (such as the core
* LookAndFeel file) should be placed. These are one-time generated files. This is the root
* directory beneath which the necessary packages and source files will be created.
* @param packageNamePrefix The package name associated with this synth look and feel. For example,
* org.mypackage.mylaf
* @param lafName The name of the laf, such as MyLAF.
* @param model The actual SynthModel to base these generated files on.
*/
public Generator(boolean full, File buildDir, File srcDir, String packageNamePrefix, String lafName,
SynthModel model) {
this.full = full;
//validate the input variables
if (packageNamePrefix == null) {
throw new IllegalArgumentException("You must specify a package name prefix");
}
if (buildDir == null) {
throw new IllegalArgumentException("You must specify the build directory");
}
if (srcDir == null) {
throw new IllegalArgumentException("You must specify the source directory");
}
if (model == null) {
throw new IllegalArgumentException("You must specify the SynthModel");
}
if (lafName == null) {
throw new IllegalArgumentException("You must specify the name of the look and feel");
}
//construct the map which is used to do variable substitution of the template
//files
variables = new HashMap<String, String>();
variables.put("PACKAGE", packageNamePrefix);
variables.put("LAF_NAME", lafName);
//generate and save references to the package-root directories.
//(That is, given the buildDir and srcDir, generate references to the
//org.mypackage.mylaf subdirectories)
buildPackageRoot = new File(buildDir, packageNamePrefix.replaceAll("\\.", "\\/"));
buildPackageRoot.mkdirs();
srcPackageRoot = new File(srcDir, packageNamePrefix.replaceAll("\\.", "\\/"));
srcPackageRoot.mkdirs();
//save the variables
this.packageNamePrefix = packageNamePrefix;
this.lafName = lafName;
this.model = model;
}
public void generate() {
//Generate the one-time files. If these files already exist, skip the
//ones that exist and create the missing ones. Register warnings for the
//already existing files.
//TODO Skip existing files, send warnings, etc.
if (full) {
try {
//create the LookAndFeel file
String template = read("resources/LookAndFeel.template");
writeSrcFile(template, variables, new File(srcPackageRoot, lafName + "LookAndFeel.java"));
} catch (IOException e) {
e.printStackTrace();
}
}
//create the painters and such.
regenerate();
}
public void regenerate() {
try {
if (full) {
//first, create the AbstractRegionPainter.java file.
String template = read("resources/AbstractRegionPainter.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "AbstractRegionPainter.java"));
//write out BlendingMode.java
template = read("resources/BlendingMode.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "BlendingMode.java"));
//create the SynthPainterImpl class
template = read("resources/SynthPainterImpl.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "SynthPainterImpl.java"));
//create the IconImpl class
template = read("resources/IconImpl.template");
writeSrcFile(template, variables, new File(buildPackageRoot, lafName + "Icon.java"));
//create the StyleImpl class
template = read("resources/StyleImpl.template");
writeSrcFile(template, variables, new File(buildPackageRoot, lafName + "Style.java"));
//write out Effect.java
template = read("resources/Effect.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "Effect.java"));
//write out EffectUtils.java
template = read("resources/EffectUtils.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "EffectUtils.java"));
//write out ShadowEffect.java
template = read("resources/ShadowEffect.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "ShadowEffect.java"));
//write out DropShadowEffect.java
template = read("resources/DropShadowEffect.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "DropShadowEffect.java"));
//write out InnerShadowEffect.java
template = read("resources/InnerShadowEffect.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "InnerShadowEffect.java"));
//write out InnerGlowEffect.java
template = read("resources/InnerGlowEffect.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "InnerGlowEffect.java"));
//write out OuterGlowEffect.java
template = read("resources/OuterGlowEffect.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "OuterGlowEffect.java"));
//write out State.java
template = read("resources/State.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "State.java"));
template = read("resources/ImageCache.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "ImageCache.java"));
template = read("resources/ImageScalingHelper.template");
writeSrcFile(template, variables, new File(buildPackageRoot, "ImageScalingHelper.java"));
}
//next, populate the first set of ui defaults based on what is in the
//various palettes of the synth model
StringBuilder uiDefaultInit = new StringBuilder();
StringBuilder styleInit = new StringBuilder();
DefaultsGenerator.generateDefaults(uiDefaultInit, styleInit, model, variables, packageNamePrefix,
buildPackageRoot);
variables.put("UI_DEFAULT_INIT", uiDefaultInit.toString());
variables.put("STYLE_INIT", styleInit.toString());
writeSrcFile(read("resources/Defaults.template"), variables,
new File(buildPackageRoot, lafName + "Defaults.java"));
} catch (IOException e) {
e.printStackTrace();
}
}
}