MobilityDesigner2CodeGenerator
Visual Mobility Designer - Using Code Generation API
Contents |
Abstract
The Code Generation API helps generates source code based in presenters combined with components. Source code is regenerated every time when user makes changes to the Design Document and switch view of the Visual Designer to the "Source". This document shows how to use the Code Generation API in the ComponentDescriptors also how to implement Code Generation Presenter.
Funtionality
Most important part of Code Generation API is a CodeSetterPresenter. Most of the developers don't have to create components from scratch. In 99% of cases the ClassCD component descriptor is reused which means basics of the code generation is already implemented. Most common Code Generation asks are:
Functionality already implemented if developer (inherited from ClassCD descriptor) - generating fields and methods (implemented in ClassCD) - lazy initialization (implemented in ClassCD)
Common tasks to implement: - generating constructor for new component (from properties) - assigning values during code initialization (from properties) - creating some custom code during initialization and after initialization (optional)
Most of this tasks could be achieved using CodeSetterPresenter.
Code generated for the LoginScreen component. The LoginScreen descriptor derives from full chain of descriptors but in this case only two descriptors generate code: ClassCD and LoginScreenCD (as it's shown in the comments):
...
private LoginScreen loginScreen; // ClassCD
...
public LoginScreen getLoginScreen() { // ClassCD
if (loginScreen == null) { // ClassCD
// write pre-init user code here // ClassCD
loginScreen = new LoginScreen(getDisplay()); // LoginScreenCD
loginScreen.setLabelTexts("Username", "Password"); // LoginScreenCD
loginScreen.setTitle("loginScreen"); // LoginScreenCD
loginScreen.addCommand(LoginScreen.LOGIN_COMMAND); // LoginScreenCD
loginScreen.setCommandListener(this); // LoginScreenCD
loginScreen.setBGColor(-3355444); // LoginScreenCD
loginScreen.setFGColor(0); // LoginScreenCD
loginScreen.setUseLoginButton(false); // LoginScreenCD
loginScreen.setLoginButtonText("Login"); // LoginScreenCD
// write post-init user code here // ClassCD
} // ClassCD
return loginScreen; // ClassCD
}
This part describes how code shown above was created.
In most of the cases developers should follow pattern for defining Code Generation in ComponentDescriptor as is shown below:
This code is part of the LoginScreenCD component descriptor. (vmd.midpnb module)
private Presenter createSetterPresenter () {
return new CodeSetterPresenter () // 1
.addParameters (MidpCustomCodePresenterSupport.createDisplayParameter ()) // 2
.addParameters(MidpParameter.create(PROP_BGK_COLOR, PROP_FRG_COLOR, PROP_USERNAME, PROP_PASSWORD, PROP_LOGIN_TITLE,
PROP_USE_LOGIN_BUTTON, PROP_USERNAME_LABEL, PROP_PASSWORD_LABEL, PROP_LOGIN_BUTTON_TEXT)) // 2
.addSetters (MidpSetter.createConstructor (TYPEID, MidpVersionable.MIDP_2).addParameters (MidpCustomCodePresenterSupport.PARAM_DISPLAY)) // 3
.addSetters(MidpSetter.createSetter("setBGColor", MidpVersionable.MIDP).addParameters(PROP_BGK_COLOR)) // 4
.addSetters(MidpSetter.createSetter("setFGColor", MidpVersionable.MIDP).addParameters(PROP_FRG_COLOR)) // 4
.addSetters(MidpSetter.createSetter("setPassword", MidpVersionable.MIDP).addParameters(PROP_PASSWORD)) // 4
.addSetters(MidpSetter.createSetter("setUsername", MidpVersionable.MIDP).addParameters(PROP_USERNAME)) // 4
.addSetters(MidpSetter.createSetter("setLoginTitle", MidpVersionable.MIDP).addParameters(PROP_LOGIN_TITLE)) //4
.addSetters(MidpSetter.createSetter("setUseLoginButton", MidpVersionable.MIDP).addParameters(PROP_USE_LOGIN_BUTTON)) // 4
.addSetters(MidpSetter.createSetter("setLabelTexts", MidpVersionable.MIDP).addParameters(PROP_USERNAME_LABEL, PROP_PASSWORD_LABEL)) // 4
.addSetters(MidpSetter.createSetter("setLoginButtonText", MidpVersionable.MIDP).addParameters(PROP_LOGIN_BUTTON_TEXT)); // 4
}
Presenter is created inside of the createSetterPresenter() method in the same ComponentDescriptor class
protected List<? extends Presenter> createPresenters() {
return Arrays.asList(
...
createSetterPresenter(),
...
);
}
Line by line explanation for Code Generation code in the LoginScreenCD descriptor (method createSetterPresenter() numbers represent). Points 1,2,3,4 represent lines in the code shown above also marked as 1,2,3,4 in code comments.
1) New CodeSetterPresenter is created
return new CodeSetterPresenter()
2) Defining parameters used by code generation for "code setters" Method responsible for adding parameters:
CodeSetterPresenter addParameters (Parameter... parameters)
Names of the parameters (properties) are defined at the beginning of the LoginScreenCD descriptor and parameters for code generation are added in the lines of code markes as 2 in the code :
...
//(Properties) Parameter names
public static final String PROP_USERNAME = "username"; //NOI18N
public static final String PROP_PASSWORD = "password"; //NOI18N
public static final String PROP_USE_LOGIN_BUTTON = "useButton"; //NOI18N
public static final String PROP_LOGIN_TITLE = "loginTitle"; //NOI18N
public static final String PROP_USERNAME_LABEL = "usernameLabel"; //NOI18N
public static final String PROP_PASSWORD_LABEL = "passwordLabel"; //NOI18N
public static final String PROP_BGK_COLOR = "backgroundColor"; //NOI18N
public static final String PROP_FRG_COLOR = "foregroungColor"; //NOI18N
public static final String PROP_LOGIN_BUTTON_TEXT = "loginButtonText"; //NOI18N
...
.addParameters (MidpCustomCodePresenterSupport.createDisplayParameter ())
.addParameters(MidpParameter.create(PROP_BGK_COLOR, PROP_FRG_COLOR, PROP_USERNAME, PROP_PASSWORD, PROP_LOGIN_TITLE,
PROP_USE_LOGIN_BUTTON, PROP_USERNAME_LABEL, PROP_PASSWORD_LABEL, PROP_LOGIN_BUTTON_TEXT))
3) Defining code generation for components constructors Constructor could be define using following method
.addSetters(MidpSetter.createConstructor(TypeID type, MidpVersionable version).addParameters(String parameterName))
The LoginScreenCD has only one possible constructor: Generated Code:
loginScreen = new LoginScreen(getDisplay());
There is only one argument in the LoginScreen constructor and its defined as MidpCustomCodePresenterSupport.PARAM_DISPLAY. Full definition of the LoginScreen constructor:
.addSetters (MidpSetter.createConstructor (TYPEID, MidpVersionable.MIDP_2).addParameters (MidpCustomCodePresenterSupport.PARAM_DISPLAY))
Another good example of construcotr defenition is the Form component (FormCD descriptor). The Form component can have two possible constructors and both are defined below: Generated Code:
form = new Form("Title Name");
First constructor has only one parameter which is represented by DisplayableCD.PROP_TITLE. Definition of constructor code generation
.addSetters(MidpSetter.createConstructor(TYPEID, MidpVersionable.MIDP).addParameters(DisplayableCD.PROP_TITLE))
and second possibility constructor which has parameter title like previous one and array of items added to the object Form. Generated Code:
form = new Form("Title Name", new Item[] { getStringItem(), getImageItem() });
Definition of the code generation for this constructor
.addSetters(MidpSetter.createConstructor(TYPEID, MidpVersionable.MIDP).addParameters(DisplayableCD.PROP_TITLE, PROP_ITEMS))
__4) Setting additional properties:
First example: Code generation for "setPassword" in LoginScreen Generated code:
loginScreen.setPassword("Some password");
In this example setPasword method is created based on the property value "PROP_PASSWORD" in the LoginScreen component. This code is generated only if property PROP_PASSWORD is not null. Presenter definition
.addSetters(MidpSetter.createSetter("setPassword", MidpVersionable.MIDP).addParameters(PROP_PASSWORD))
Very similar example but with different argument (property/parameter PROP_BGK_COLOR). Generated code
loginScreen.setBGColor(-3355444);
.addSetters(MidpSetter.createSetter("setBGColor", MidpVersionable.MIDP).addParameters(PROP_BGK_COLOR))
Remember to define all parameters which will be used in additional "setters" just like is shown in section 2)
Examples
Many examples of code generation can be found in modules vmd.midp and vmd.midpnb. Almost all ComponentDescription contain use cases of Code Generation API. Presenters used for code generation are marked in comments as "// code" (method createPresenters() class ComponentDescriptors).
Full listing of LoginScreenCD
LoginScreenCD class:
public final class LoginScreenCD extends ComponentDescriptor {
public static final TypeID TYPEID = new TypeID(TypeID.Kind.COMPONENT, "org.netbeans.microedition.lcdui.LoginScreen"); // NOI18N
public static final String ICON_PATH = "org/netbeans/modules/vmd/midpnb/resources/login_screen_16.png"; // NOI18N
public static final String ICON_LARGE_PATH = "org/netbeans/modules/vmd/midpnb/resources/login_screen_32.png"; // NOI18N
public static final String PROP_USERNAME = "username"; //NOI18N
public static final String PROP_PASSWORD = "password"; //NOI18N
public static final String PROP_USE_LOGIN_BUTTON = "useButton"; //NOI18N
public static final String PROP_LOGIN_TITLE = "loginTitle"; //NOI18N
public static final String PROP_USERNAME_LABEL = "usernameLabel"; //NOI18N
public static final String PROP_PASSWORD_LABEL = "passwordLabel"; //NOI18N
public static final String PROP_BGK_COLOR = "backgroundColor"; //NOI18N
public static final String PROP_FRG_COLOR = "foregroungColor"; //NOI18N
public static final String PROP_LOGIN_BUTTON_TEXT = "loginButtonText"; //NOI18N
public static final String USERNAME_LOGIN = NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_Username"); //NOI18N
public static final String PASSWORD_LOGIN = NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_Password"); //NOI18N
public static final String LOGIN_BUTTON_TEXT = NbBundle.getMessage(LoginScreenCD.class, "LBL_LoginScreen_LoginButtonScreen"); //NOI18N
static {
MidpTypes.registerIconResource(TYPEID, ICON_PATH);
}
public TypeDescriptor getTypeDescriptor() {
return new TypeDescriptor(CanvasCD.TYPEID, TYPEID, true, true);
}
public VersionDescriptor getVersionDescriptor() {
return MidpVersionDescriptor.MIDP_2;
}
public List<PropertyDescriptor> getDeclaredPropertyDescriptors() {
return Arrays.asList(
new PropertyDescriptor(PROP_USERNAME, MidpTypes.TYPEID_JAVA_LANG_STRING, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_PASSWORD, MidpTypes.TYPEID_JAVA_LANG_STRING, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_USE_LOGIN_BUTTON, MidpTypes.TYPEID_BOOLEAN, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_LOGIN_TITLE, MidpTypes.TYPEID_JAVA_LANG_STRING, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_BGK_COLOR, MidpTypes.TYPEID_INT, MidpTypes.createIntegerValue(-3355444), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_FRG_COLOR, MidpTypes.TYPEID_INT, MidpTypes.createIntegerValue(-16777216), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_USERNAME_LABEL, MidpTypes.TYPEID_JAVA_LANG_STRING, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_PASSWORD_LABEL, MidpTypes.TYPEID_JAVA_LANG_STRING, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2),
new PropertyDescriptor(PROP_LOGIN_BUTTON_TEXT, MidpTypes.TYPEID_JAVA_LANG_STRING, PropertyValue.createNull(), true, true, MidpVersionable.MIDP_2)
);
}
private static DefaultPropertiesPresenter createPropertiesPresenter() {
return new DefaultPropertiesPresenter(DesignEventFilterResolver.THIS_COMPONENT)
.addPropertiesCategory(MidpNbPropertiesCategories.CATEGORY_LOGIN)
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_Username"), // NOI18N
PropertyEditorString.createInstance(NbBundle.getMessage(LoginScreenCD.class,
"LBL_LoginScreen_Username")), PROP_USERNAME) // NOI18N
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_Password"), // NOI18N
PropertyEditorString.createTextFieldInstance(NbBundle.getMessage(LoginScreenCD.class,
"LBL_LoginScreen_Password")), PROP_PASSWORD) // NOI18N
.addPropertiesCategory(MidpPropertiesCategories.CATEGORY_PROPERTIES)
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_UsernameLabel"), // NOI18N
PropertyEditorString.createInstance(NbBundle.getMessage(LoginScreenCD.class,
"LBL_LoginScreen_Username")), PROP_USERNAME_LABEL) // NOI18N
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_PasswordLabel"), // NOI18N
PropertyEditorString.createInstance(NbBundle.getMessage(LoginScreenCD.class,
"LBL_LoginScreen_Password")), PROP_PASSWORD_LABEL) // NOI18N
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_UseLoginButton"), // NOI18N
PropertyEditorBooleanUC.createInstance(), PROP_USE_LOGIN_BUTTON)
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_LoginTitle"), // NOI18N
PropertyEditorString.createInstance(NbBundle.getMessage(LoginScreenCD.class,
"LBL_LoginScreen_LoginTitle")), PROP_LOGIN_TITLE) // NOI18N
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_BackgroundColor"), // NOI18N
new PropertyEditorColorChooser(true), PROP_BGK_COLOR)
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_ForegroundColor"), // NOI18N
new PropertyEditorColorChooser(true), PROP_FRG_COLOR)
.addProperty(NbBundle.getMessage(LoginScreenCD.class, "DISP_LoginScreen_LoginButtonText"), // NOI18N
PropertyEditorString.createInstance(NbBundle.getMessage(LoginScreenCD.class,
"LBL_LoginScreen_LoginButtonText_LABEL")), PROP_LOGIN_BUTTON_TEXT); //NOI18N
}
private Presenter createSetterPresenter () {
return new CodeSetterPresenter ()
.addParameters (MidpCustomCodePresenterSupport.createDisplayParameter ())
.addParameters(MidpParameter.create(PROP_BGK_COLOR, PROP_FRG_COLOR, PROP_USERNAME, PROP_PASSWORD, PROP_LOGIN_TITLE,
PROP_USE_LOGIN_BUTTON, PROP_USERNAME_LABEL, PROP_PASSWORD_LABEL, PROP_LOGIN_BUTTON_TEXT))
.addSetters (MidpSetter.createConstructor (TYPEID, MidpVersionable.MIDP_2).addParameters (MidpCustomCodePresenterSupport.PARAM_DISPLAY))
.addSetters(MidpSetter.createSetter("setBGColor", MidpVersionable.MIDP).addParameters(PROP_BGK_COLOR)) //NOI18N
.addSetters(MidpSetter.createSetter("setFGColor", MidpVersionable.MIDP).addParameters(PROP_FRG_COLOR)) //NOI18N
.addSetters(MidpSetter.createSetter("setPassword", MidpVersionable.MIDP).addParameters(PROP_PASSWORD)) //NOI18N
.addSetters(MidpSetter.createSetter("setUsername", MidpVersionable.MIDP).addParameters(PROP_USERNAME)) //NOI18N
.addSetters(MidpSetter.createSetter("setLoginTitle", MidpVersionable.MIDP).addParameters(PROP_LOGIN_TITLE)) //NOI18N
.addSetters(MidpSetter.createSetter("setUseLoginButton", MidpVersionable.MIDP).addParameters(PROP_USE_LOGIN_BUTTON)) //NOI18N
.addSetters(MidpSetter.createSetter("setLabelTexts", MidpVersionable.MIDP).addParameters(PROP_USERNAME_LABEL, PROP_PASSWORD_LABEL)) //NOI18N
.addSetters(MidpSetter.createSetter("setLoginButtonText", MidpVersionable.MIDP).addParameters(PROP_LOGIN_BUTTON_TEXT)); //NOI18N
}
protected List<? extends Presenter> createPresenters() {
return Arrays.asList (
//properties
createPropertiesPresenter(),
// code
createSetterPresenter(),
MidpCodePresenterSupport.createAddImportPresenter(),
// actions
AddActionPresenter.create(AddActionPresenter.ADD_ACTION, 10, CommandCD.TYPEID),
// screen
new LoginScreenDisplayPresenter()
);
}
@Override
public void postInitialize(DesignComponent component) {
super.postInitialize(component);
MidpProjectSupport.addLibraryToProject (component.getDocument (), AbstractInfoScreenCD.MIDP_NB_LIBRARY_BASIC); //NOI18N
}
@Override
protected void gatherPresenters(ArrayList<Presenter> presenters) {
DocumentSupport.removePresentersOfClass(presenters, AddActionPresenter.class);
DocumentSupport.removePresentersOfClass(presenters, DisplayableDisplayPresenter.class);
MidpActionsSupport.addUnusedCommandsAddActionForDisplayable(presenters);
super.gatherPresenters(presenters);
}
}
contact: Karol Harezlak

