概述
Smooks configuration editor 在早期的版本是一个具有2个页面的多页编辑器。除了其中一个文本页,另外一个页面是一个基于Master-Details的编辑器,称为Design Page。
Smooks configuration editor 是利用EMF,通过Smooks所定义的配置文件的XSD创建对应的EMF模型,所有的EMF模型相关代码都放在了org.jboss.tools.smooks.core 插件项目中。
在上面所提到的设计页面如下图所示:
该页面左侧是一个TreeViewer,右侧则在选中左侧Viewer中的item后显示其属性编辑界面。
而左侧TreeViewer的输入模型正是通过EMF Resource读取Smooks配置文件后得到的EMF模型,其中所有的节点都是EMF模型(或者被emf.edit包装过的模型),右侧的Details界面显示了被选中EMF模型的属性。
熟悉Eclipse开发的读者应该知道,在创建Master-Details类型的FormPage时,我们需要把模型类型以及它所对应的GUI注册一遍,这样一来,当Master的Selection改变的时候,它才能够利用新的模型类型取出对应的GUI,然后重新创建Details的GUI。
Smooks configuration editor 虽然也是使用Master-Details,但它并没有为每一个模型注册对应的GUI页面,而是用这些模型的共同的父类:EObject作为模型类型进行注册,这意味着,每当左侧TreeViewer发生了SelectionChange后,Details页面每次都只能从注册的页面中得到同一个GUI对象,这个GUI对象就是:org.jboss.tools.smooks.configuration.editors.SmooksStuffPropertyDetailPage
但这并不意味着左侧的Details页面不会根据不同模型而改变。Details页面有一个selectionChange的方法,是当模型选择发生改变后触发的。SmooksStuffPropertyDetailPage实现了这个方法:
public void selectionChanged(IFormPart part, ISelection selection) {
Object oldModel = getModel();
setOldModel(oldModel);
…………
this.itemPropertySource = (IItemPropertySource) editingDomain.getAdapterFactory().adapt(getModel(),
IItemPropertySource.class);
………
………
if (getOldModel() != getModel()) {
if (propertyComposite != null) {
propertyComposite.dispose(); // remove the old properties’ GUI
propertyComposite = new Composite(propertyMainComposite, SWT.NONE);
}
createStuffDetailsComposite(propertyComposite); // recreate the GUI for new model
}
}
从代码中可以看出,每当模型改变的时候,如果是一个新的模型,而不是当前模型,那显示模型属性的Composite会被dispose掉,然后重新创建一个新的Composite对象,再根据新模型创建新的模型属性GUI。
如何根据EMF模型创建属性GUI.
我们都知道,emf.edit会为每一个EMF模型生成一个XXXXXXXItemProvider,然后生成一个XXXXItemProviderFactory的类,来维护为这些ItemProvider。
这些ItemProvider具有很多功能,它实现了很多常见的为GUI显示准备的接口,比如:IItemLabelProvider, ITreeItemContentProvider , IItemPropertySource。其中IItemPropertySource正是获取模型属性的接口。
Smooks configuration editor在初始化的时候,创建了AdapterFactoryEditingDomain,并把这些ProviderFactory注册到这个EditingDomain中,这样一来,就可以通过EditingDomain获得对应的XXXItemProvider。
SmooksStuffPropertyDetailPage正是通过ItemPropertySource获得每一个属性的Descriptor,然后根据这些Descriptor来创建出对应的GUI。
创建Property的GUI分成两种形式:
1. 创建默认的Property GUI。这种方法会为每一个对应的属性模型创建出默认的GUI。
2. 使用注册好的PropertyUICreator创建。通过PropertyUICreator来创建出属性的GUI,如果Creator所创建出的GUI为NULL,SmooksStuffPropertyDetailPage会通过第一种方法创建出GUI来。
PropertyUICreator是一个接口:org.jboss.tools.smooks.configuration.editors.IPropertyUICreator,只要实现了这个接口,并把模型类型和该接口的实力注册到单态类PropertyUICreatorManager中,SmooksStuffPropertyDetailPage就能根据模型类型获得IPropertyUICreator的实例。
现在回到代码中,在SmooksStuffPropertyDetailPage中有一个createStuffDetailsComposite的方法:
protected void createStuffDetailsComposite(Composite detailsComposite) {
try {
.......
// Get the PropertyUICreator instance
IPropertyUICreator creator = PropertyUICreatorManager.getInstance().getPropertyUICreator(getModel());
// Get the Property Descriptor from IItemPropertySource instance.
List<IItemPropertyDescriptor> propertyDes = itemPropertySource.getPropertyDescriptors(getModel());
if (creator != null) {
// Create the Property Extention-GUI via PropertyUICreator
}
for (int i = 0; i < propertyDes.size(); i++) {
IItemPropertyDescriptor pd = propertyDes.get(i);
EAttribute attribute = (EAttribute) pd.getFeature(getModel());
if (attribute.isRequired()) {
// Create the required attribute GUI first
AttributeFieldEditPart editPart = createAttributeUI(detailsComposite, pd, creator);
........
}
}
for (int i = 0; i < propertyDes.size(); i++) {
IItemPropertyDescriptor pd = propertyDes.get(i);
EAttribute attribute = (EAttribute) pd.getFeature(getModel());
if (!attribute.isRequired()) {
// Create the un-required attribute GUI
AttributeFieldEditPart editPart = createAttributeUI(detailsComposite, pd, creator);
.......
}
}
if (creator != null) {
// Create attribute GUI via PropertyUICreator
}
........
} catch (Exception e) {
// ignore
}
}
如果从代码中不容易看出整个创建流程,下图能帮助你去理解:
根据PropertyDescriptor创建GUI
在SmooksStuffPropertyDetailPage中有一个方法,是负责根据IPropertyDescriptor创建GUI的。
protected AttributeFieldEditPart createAttributeUI(Composite detailsComposite,
IItemPropertyDescriptor propertyDescriptor, IPropertyUICreator creator) {
final IItemPropertyDescriptor itemPropertyDescriptor = propertyDescriptor;
EAttribute feature = (EAttribute) itemPropertyDescriptor.getFeature(getModel());
AttributeFieldEditPart editPart = null;
if (createDefault) {
EClassifier typeClazz = feature.getEType();
boolean hasCreated = false;
if (typeClazz instanceof EEnum) {
....
}
if (typeClazz.getInstanceClass() == String.class) {
......
}
......
}
return editPart;
}
不难看出,根据输入Property的Class类型,创建出不同的GUI。而创建这些对应GUI的具体实现,是在 SmooksUIUtils中实现的。
值得一提的是,所创建出来的GUI,都会自动添加监听器,去监听GUI的变化(比如,文本框的变化),然后根据变化将值回写到Property中,我们看SmooksUIUtils中一个代码片段 (from line 945 ) :
if (itemPropertyDescriptor != null) {
// add modify listener to the ValueText control
valueText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
// Get the value of this property
Object editValue = getEditValue(itemPropertyDescriptor, fm);
if (editValue != null) {
String vt = valueText.getText();
if (vt == null || vt.length() == 0) {
// if the text is null , un-set the property value.
itemPropertyDescriptor.setPropertyValue(fm, null);
} else {
// set the new value to this property
if (!editValue.equals(vt)) {
itemPropertyDescriptor.setPropertyValue(fm, vt);
}
}
} else {
// set the new value to this property
itemPropertyDescriptor.setPropertyValue(fm, valueText.getText());
}
}
});
}
ModelPanelCreator
ModelPanelCreator其实是将SmooksStuffPropertyDetailPage中创建属性GUI的代码复制了出来,实现了一个独立的类,这样就可以在其他的非Master-Details的GUI中使用了。
该类主要应用可以参考:
org.jboss.tools.smooks.configuration.editors.NewOrModifySmooksElementDialog
org.jboss.tools.smooks.configuration.editors.SmooksConfigurationOverviewPage
org.jboss.tools.smooks.edimap.editors.EDIMapFormPage
没有评论:
发表评论