2009年9月11日星期五

Smooks tools – Generate GUIs for attributes of EMF model

Overview

In the early version , the Smooks configuration editor is a multipe-page editor. Except a Text page , the other page is a Form page base on Master-Details editor , we call it “Design Page”.

Smooks tools use the EMF to create the related EMF model via the XSD files come from Smooks , all of them put in the org.jboss.tools.smooks.core plug-in project.

This is the “Design Page” :

smookstools_message_filter_page

On the left-side , there is a TreeViewer , right-side panel displays the GUIs.

The input models for the left-side TreeViewer are the EMF models what are loaded from the Smooks configuration file by EMF Resource , all of the tree nodes are EMF model ( or the warp model provide by emf.edit) , the right-side panel show the GUIs for the attributes of EMF model which is selected on.

The guys who are familiar with the Eclipse plguin development should know that if we developed the Master-Details type FromPage , we need to regist the model type and the GUI class related to the mode , so when the selection changed from the Master , the Details will get the GUI via the new model type and re-create the GUI.

Although the Smooks configuration editor use the Master-Details , it didn’t regist the different GUI for every different model , it regist the GUI like this :

detailsPart.registerPage(EObject.class, new SmooksStuffPropertyDetailPage((SmooksMultiFormEditor) this.formEditor));

It use the EObject as the model type , it means that , when the left-side TreeViewer fire the “selection change event” , the Details page can only the same GUI instance evenrytime , and this GUI class is : org.jboss.tools.smooks.configuration.editors.SmooksStuffPropertyDetailPage

But it dosen’t mean that the Details page can’t show the different GUI for different model. Details page has a “selectionChange” method , this method will be called when the selection was changed in Master page.

This is the implemention for the method of 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
    }
}

We can know that from the codes : When the model selection was changed , if it’s a new model (different with the current model) , the Composite which displayed the GUIs for the model attributes will be disposed , and then create a new Composite instance and create new attributes GUI via the new model.

How to create attributes GUI via EMF model

We know that , emf.edit can generate a ******ItemProvider for each EMF model , and generate a ******ItemProviderFactory to manage those ItemProvider.

The ItemProvider has many functions , it implements many interface for common GUI display , such as : IItemLabelProvider (ILabelProvider) , IITreeItemContentProvider ( IStructuredContentProvider) , IItemPropertySource ( PropertySource). One of them , the IItemPropertySource can get the attributes’ informations from the EMF model.

When initialize the Smooks configuration editor , I create an “AdapterFactoryEditingDomain” , and registe those ProviderFactory into this EditingDomain , so the ItemProvider can be get from the EditingDomain : ( in the AbstractSmooksFormEditor , line 223)

protected void initEditingDomain() {
    adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
    // add smooks 1.1.2 EMF item provider
    adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
    .........
    // add smooks 1.2 EMF item provider
    adapterFactory.addAdapterFactory(new Json12ItemProviderAdapterFactory());
    .........
    BasicCommandStack commandStack = new BasicCommandStack();
    handleCommandStack(commandStack);
    editingDomain = new AdapterFactoryEditingDomain(adapterFactory, commandStack, new HashMap<Resource, Boolean>());
}

SmooksStuffPropertyDetailPage just use the ItemPropertySource to get the Descriptor of each property, and use those Descriptors to generate the related GUIs.

There are two ways for generating Properties’ GUI:

1. Generate the default Property GUI. This way will create a default GUI for each property.

2. Generate the Property GUI by PropertyUICreator. Use the PropertyUICreator to generate the properties’ GUI , if it generate NULL for the properties , SmooksStuffPropertyDetailPage will use the first way to generate the GUI again.

What’s the PropertyUICreator?

PropertyUICreator is a interface : org.jboss.tools.smooks.configuration.editors.IPropertyUICreator , If implement the interface and registe the mode type and the related PropertyUICreator instance into the PropertyUICreatorManager , SmooksStuffPropertyDetailPage can get the IPropertyUICreator instance via each type model.

Let’s return to the codes , there is a method : “createStuffDetailsComposite” in the SmooksStuffPropertyDetailPage :

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
    }
}

 

If the codes is hard to understand , maybe the flow diagram can help you :

myImage

 

Generate GUI via PropertyDescriptor

There is a method in SmooksStuffPropertyDetailPage , its duty is generate the GUI via IPropertyDescriptor instance.

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;
}

It’s not hard to see , get the Class type and generate different GUI with this type. In the SmooksUIUtils class , we can see how to generate the GUI.

When generate the GUI , SmooksUIUtils will add a Listener for the GUI control to monitor the modification of GUI controls , when the GUI control was modified , the properties’ value will be change.

Let’s look a fragment of 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

Actually , I copy the codes which generate the property GUI form the SmooksStuffPropertyDetailPage and create a new Class : ModelPanelCreator. So I can generate the EMF model attributes’ GUI everywhere.

Those class use the ModelPanelCreator:

org.jboss.tools.smooks.configuration.editors.NewOrModifySmooksElementDialog

org.jboss.tools.smooks.configuration.editors.SmooksConfigurationOverviewPage

org.jboss.tools.smooks.edimap.editors.EDIMapFormPage

1 条评论:

  1. 對於一個看不懂的人來講,真是亂麻耶!(抱歉,講話直)
    祝好.^-^

    回复删除