Customization

Top

Managing Resources

Resource Loader

The class ResourceLoader (src) can be used to handle resource loading. This class uses internally the Empty Resource Initializer.

Empty Resource Initializer

If you need to initialize your model, for the first use, you can define an implementation of EmptyResourceInitializer (src). When the main resource will be found empty, your code will be executed.

Editing Domain Finder

The class EditingDomainFinder (src) can be inherited to provide a specific way to find the editign domain.

Resource Save Manager

Resource saving is delegated to ResourceSaveManager (src) which, by defaults only saves the passed Resource (src). You can inject your own save manager and implement the method precondition(Resource), for instance, you may want to validate the resource before saving, and in case the validation fails to return false. If the precondition is false the default implementation will not save the resource (and in turn will return false).

Validate Resource Save Manager

We provide an example of custom resource save manager: ValidateResourceSaveManager (src), we show here only relevant parts to give an example:

public class ValidateResourceSaveManager extends ResourceSaveManager {

    @Override
    protected boolean precondition(Resource resource) {
        return super.precondition(resource) && validateModel(resource);
    }

    protected boolean validateModel(Resource resource) {
        for (EObject eObject : resource.getContents()) {
            Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObject);
            if (diagnostic.getSeverity() == Diagnostic.ERROR) {
                // SKIPPED: present the errors
                return false;
            } else if (diagnostic.getSeverity() == Diagnostic.WARNING) {
                // SKIPPED: present the warnings
            }
        }
        return true;
    }
}

Top

Providers

Features Provider

This can be done with Parsley DSL too!

TODO: merge delle 2 versioni

Prima versione

To customize the feature list it can be injected a FeaturesProvider (src). The default is to return the list of all the features in the EClass, but the programmer can customize it (for instance, by returning only a superset, or using a different order) on an EClass-based strategy. The customization can be done redefining buildMap and adding mappings.

protected void buildMap(EClassToEStructuralFeatureMap map) {
    super.buildMap(map);
    map.mapTo(LIBRARY,LIBRARY__NAME, ADDRESSABLE__ADDRESS);
}

In the example we specify that for the EClass Library the feature that are to be displayed are name and address.

Seconda versione

When the framework builds components according to the EStructuralFeature (src)s of a given EClass (src) it relies on an injected FeaturesProvider (src). The default behavior is to simply return all the features of the a given EClass, in the order they are defined in the EClass; you may want to provide a custom implementation by redefining the method List<EStructuralFeature> getFeatures(EClass), or List<EStructuralFeature> getFeatures(EObject), for instance by returning the features ordered according to their name (the following snippet uses an utility class from the framework)

public class OrderedEStructuralFeaturesProvider 
    extends FeaturesProvider {

    @Inject
    EStructuralFeatureNameComparator comparator;
    
    @Override
    public List<EStructuralFeature> getFeatures(EClass eClass) {
        List<EStructuralFeature> features = super.getFeatures(eClass);
        Collections.sort(features, 
            new EStructuralFeatureNameComparator());
        return features;
    }
}

Alternatively, you can set the mappings, i.e., specify the structural features you want to be used given an EClass, by implementing the method buildMap, which receives the FeaturesProvider.EClassToEStructuralFeatureMap (src) that can be filled with the method mapTo; for instance, using the EMF extended library example, this customization will return only the name and address features for Library, the firstName, lastName and address for Person, and the firstName, lastName and books (but not address) for Writer (which inherits from Person).

import static org.eclipse.emf.examples.extlibrary.EXTLibraryPackage.Literals.*;
import org.eclipse.emf.parsley.ui.provider.EStructuralFeaturesProvider;

public class LibraryEStructuralFeaturesProvider extends
        FeaturesProvider {

    @Override
    protected void buildMap(EClassToEStructuralFeatureMap map) {
        super.buildMap(map);
        map.mapTo(LIBRARY,
                LIBRARY__NAME, ADDRESSABLE__ADDRESS);
        map.mapTo(PERSON,
                PERSON__FIRST_NAME, PERSON__LAST_NAME,
                ADDRESSABLE__ADDRESS);
        map.mapTo(WRITER,
                PERSON__FIRST_NAME, PERSON__LAST_NAME,
                WRITER__BOOKS);
    }
}

Another possibility is to build a map which relies on Strings both for the EClass (src) and for the list of EStructuralFeature (src); note that the name of the EClass (src) should be obtained by using getInstanceClassName(); you can also combine the two approaches (in that case the map built with buildMap has the precedence):

import static org.eclipse.emf.examples.extlibrary.EXTLibraryPackage.Literals.*;
import org.eclipse.emf.parsley.ui.provider.FeaturesProvider;

public class LibraryEStructuralFeaturesAsStringsProvider extends
        FeaturesProvider {

    @Override
    protected void buildMap(EClassToEStructuralFeatureMap map) {
        super.buildMap(map);
        map.mapTo(LIBRARY, LIBRARY__NAME, ADDRESSABLE__ADDRESS);
    }

    @Override
    protected void buildStringMap(
            EClassToEStructuralFeatureAsStringsMap stringMap) {
        super.buildStringMap(stringMap);
        stringMap.mapTo(PERSON.getInstanceClassName(), "firstName""lastName",
                "address");
        stringMap.mapTo(WRITER.getInstanceClassName(), "firstName""lastName",
                "books");

    }
}

Features Column Provider

As an extension, you can use the FeaturesColumnProvider (src): the customizations will be applied only to tables, not to Forms.

Feature Caption Provider

This can be done with Parsley DSL too! The FeatureCaptionProvider (src) provides captions for the features. It can be customized, with injection (see Injection paragraph), to customize the caption label on the left of each control in a form and the headers in a table's columns. The framework use a polimorphic mechanism to find customizations, so that It can be written a method with a specific signature build by the keyword 'text' followed by the EClass and the EStructuralFeature. All parts of the name are separated by an underscore character and the method must accept a parameter of type EStructuralFeature.

In the following example we specify the caption text for the feature 'Author' of Book and the feature 'Name' for Writer.

public String text_Book_author(final EStructuralFeature feature) {
    return "Wrote by:";
}

public String text_Writer_name(final EStructuralFeature feature) {
    return "Name:";
}

Form Feature Caption Provider

The FormFeatureCaptionProvider (src) can be used if you want to define the description only for the form. For example using the Tree Form your definition will not be used in the tree.

In this case you can also define a method the returns directly the control, like in the example below. In such methods there is another parameter that is the parent composite.

public Label label_Writer_name(Composite parent, EStructuralFeature feature) {
    Label label = defaultLabel(parent, feature);
    label.setBackground(getFormToolkit().getColors().getColor(IFormColors.TITLE));
    return label;
}

Viewer Label Provider

The Label Provider can be customized by providing a specific implementation of ILabelProvider and injecting it in the spefic module (TODO). EMF Parsley provides such an implementation with the class ViewerLabelProvider (src) that is inteded to be surclassed by the programmer to provides specific implementations like in the example below.

public class CustomLibraryLabelProvider extends ViewerLabelProvider {

    @Inject
    public CustomLibraryLabelProvider(AdapterFactoryLabelProvider delegate) {
        super(delegate);
    }

    public String text(Book book) {
        return "Book: " + book.getTitle();
    }

    public String image(Book book) {
        return "book2.png";
    }

    public String text(Borrower b) {
        return "Borrower: " + b.getFirstName();
    }
}

Viewer Content Provider

The programmer can provide a specific implementation of IContentProvider by injecting it in the spefic module (TODO). EMF Parsley provides an implementation with the class ViewerContentProvider (src) that can be easily used to specify the children of all object on the tree, like in the example below.

public class CustomLibraryViewerContentProvider extends ViewerContentProvider {

    @Inject
    public CustomLibraryViewerContentProvider(AdapterFactory adapterFactory) {
        super(adapterFactory);
    }

    public Object children(Library library) {
        return library.getBooks();
    }

    public Object children(Book book) {
        ArrayList<Object> children = new ArrayList<Object>();
        Writer author = book.getAuthor();
        if (author != null) {
            children.add(author);
        }
        children.addAll(book.getBorrowers());
        return children;
    }
}

Proposal Provider

This can be done with Parsley DSL too! Some controls use a list of proposal to help the end user experince: for example the combo box has a list of proposal, but also the simple text can use the proposal to assist and correct the hand-writed values. For each feature it can be specified a list of proposals using a method that starts with the keyword 'proposals' followed byt the EClass and Feature undescore-character-separated.

public List<?> proposals_Book_author(Book book) {
    List<Object> proposals = new LinkedList<Object>();
    Writer writer = EXTLibraryFactory.eINSTANCE.createWriter();
    writer.setFirstName("Fake");
    writer.setLastName("Writer");
    proposals.add(writer);
    writer = EXTLibraryFactory.eINSTANCE.createWriter();
    writer.setFirstName("Fake");
    writer.setLastName("Writer2");
    proposals.add(writer);
    return proposals;
}

Viewer Context Menu Factory

ViewerContextMenuFactory (src)

Table Column Label Provider

TableColumnLabelProvider (src)

Top

Selection And Menu

Emf Selection Helper

EmfSelectionHelper (src)

Top

Builders

Table Viewer Builder

TableViewerBuilder (src)

Table Viewer Column Builder

TableViewerColumnBuilder (src)

Table Viewer Editable Column Builder

TableViewerEditableColumnBuilder (src)

Top

Factories

Form Factory

FormFactory (src)

Jface Provider Factory

ColumnLabelProviderFactory (src)

Form Control Factory

This can be done with Parsley DSL too! If you want to customize the controls on the right, it can be injected a specification of the class FormControlFactory (src). Using the same polimorphic mechanism of the labels, the programmer can write a method with the keyword 'control' followed by the EClass and EStructuralFeature undescore-character-separated. In the signature of the method must be both the DataBinding Context and the Feature Observable that can be used for databinding.

public Control control_Writer_name(DataBindingContext dbc,IObservableValue featureObservable) {
    //Creating the control
    Text text = getToolkit().createText(getParent(), "");
    text.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
    text.setBackground(getToolkit().getColors().getColor(IFormColors.TITLE));
    //Binding the control to the feature observable
    dbc.bindValue(SWTObservables.observeText(text, SWT.Modify),    featureObservable);
    return text;
}

For more info, see the other parts that are used internally by the Form Control Factory:

Tree Form Factory

TreeFormFactory (src)

Viewer Factory

ViewerFactory (src)

Viewer Factory

AdapterFactoryEditingDomain

AdapterFactory

Top

Viewers

Viewer Initializer

ViewerInitializer (src)

  • AdapterFactoryEditingDomain
  • AdapterFactory
  • ILabelProvider
  • IContentProvider