facebook
Dimitry Karpenko
Java/Eclipse developer in MyEclipse and Webclipse teams.
Posted on Mar 1st 2016


In previous articles, we’ve learned how to perform relatively simple Eclipse Sapphire customizations. Let’s try out something more complex. We’ll be creating one more editor for the android resources. This time our editor will handle not only color resources, but also another node representing string resources which are stored in another file, strings.xml.

Prerequisites

Of course, you need to understand how to use the Eclipse editor and Sapphire API. Also, please read the Custom Bindings article to familiarize yourself with concepts that will be used in this article. You need Eclipse 4 and Sapphire 9. If you are using a different version you can follow along but you may encounter some differences from what is described.

Note: You can read about creating a simple Eclipse Sapphire editor here.

Model

The model is pretty simple and similar to the model in a previous article in which both Color and String have Name and Value properties. You can look at the `com.genuitec.sapphire.integratededitor.model` package in the sample project to see details. `IAndroidResources` is an actual root model class, it holds colors and strings lists. `IIntegratedAndroidResources` and `IStringResources` are dummy model classes needed by Sapphire’s model-to-resources connection code, see below for details.

Editing and Storing

The core part of our editor is the `AndroidResourcesEditor` class. We’ll need to create two separate source pages for editing colors.xml and strings.xml. Method `createSourcePages()` is responsible for doing this.

Important:  While reading the code, be sure not to confuse the following:

  • `IAndroidResources`, `IStringResources` and related classes are model classes.  Their naming is related to Android XML resources, in our case, colors and strings.
  • Sapphire’s `XmlResource`, `RootXmlResource` and their derivatives are internal Sapphire entities.  They are responsible for binding Sapphire model data to the underlying XML DOM model, which we will use to support simultaneously editing 2 xml files.

Model Creation

To handle two separate model files, we need to have two model objects: `IAndroidResources` (having all of our properties) and `IIntegratedAndroidResources` (a dummy type to be bound with the resource representing strings.xml). Strings property in `IAndroidResources` type has our custom annotation `@IntegratedListBinding`.  This annotation doesn’t provide any data and serves as a marker annotation indicating that the specified property should be persisted in a “foreign” file, in our case strings.xml.

To have a single editor for two xml files, we’ll need to have our model bound to 2 different `RootXmlResource` entities. Let’s see how it’s done. Take a look at the method `createModel()`.

protected Element createModel() {
   	 XmlEditorResourceStore foreignResStore = new XmlEditorResourceStore( this, this.stringsSourceEditor );
   	 foreignResource = new RootXmlResource( foreignResStore );
    	RootXmlResource mainRes = createMainResource();
   	 this.androidResources = applicationElementType.instantiate( mainRes );
   	 foreignResource.init(androidResources);
    	this.integratedAndroidResources = integratedAppElementType.instantiate(
   			 new RootIntegratedResource(mainRes, foreignResource, this.androidResources, applicationElementType ) );
   	 
    	return this.integratedAndroidResources;
	}

Explained

  • Line 2—Create “foreign” resource, for strings.xml file, connected with corresponding text editor
  • Line 3—`RootXmlResource` is created for `foreignResStore`
  • Line 4—Call to “main” resource creation method. Let’s take a closer look at this method below:
    protected RootXmlResource createMainResource() {
       	 RootXmlResource mainRes = new RootXmlResource( new XmlEditorResourceStore( this, this.colorsSourceEditor ) ) {
       		 @Override
       		 protected PropertyBinding createBinding(Property property) {
       			 PropertyDef propertyDef = property.definition();
           		 PropertyBinding binding = null;
           		 if (propertyDef instanceof ListProperty) {
           			 final IntegratedListBinding customBindingAnnotation = propertyDef.getAnnotation(IntegratedListBinding.class);
           			 if (customBindingAnnotation != null) {
           				 binding = new CustomizedXmlBindingImpl((XmlResource) foreignResource);
           				 return binding;
           			 }
           		 }
       			 return super.createBinding(property);
       		 }
        	};
       	 return mainRes;
        }
    

    Here we create `RootXmlResource` with overriding `createBinding()` method. In this method, we analyze the bound field for a presence of marker `IntegratedListBinding` annotation. If annotation is present, we create `CustomizedXmlBindingImpl` binding impl, which is responsible for storing changes for specified property to “foreign” resource.

  • Line 5—“Main” element, `IAndroidResources` instance, is being created using “main” resources created above
  • Line 6—Foreign resource is initialized using our “main” element, since all of our props are defined in “main” element
  • Line 7—`IntegratedAndroidResources`, which integrates resources matching colors.xml and strings.xml, is created

The `createFormPages()` method is responsible for creating Design page. Other methods in `AndroidResourcesEditor` are pretty straightforward.

Binding

`CustomizedXmlBindingImpl` is responsible for binding some model property to a custom resource. Most of it is copied from the original Sapphire’s `StandardXmlListBindingImpl` with changes allowing it to use the custom resource (stored in `xmlResource`) field. If you need to create a binding for some other property type (Value, Element, Implied Element), you’ll need to do the same; look at the original binding code, extend the original binding class and modify its behavior to use custom resource. Some methods are copied instead of extending, because there’s a lot of private or final stuff in Sapphire code.

RootIntegratedResource

This class is aggregating two underlined resources – for colors.xml and strings.xml. It’s responsible to call `save()` for both resources when editor save is called.

Editor UI

The ResEditor.sdef file describes simple Sapphire GUI for our editor. The Editor should be registered in plugin.xml, some details on doing this can be found here: http://www.eclipse.org/sapphire/releases/9.0.4/documentation/introduction/index.html.

Let’s Try It!

You’ll need to create a sample project in your test workspace, or you can use an existing one. You will need to place two xml files, colors.xml and strings.xml, inside the same folder in your project. Sample files can be downloaded using the link below. Double-click colors.xml to launch your editor.

Eclipse Sapphire Editor Example

 

Attachments

sapphire_inteditor_tutorial—Sample project
XMLfiles.zip—Sample colors.xml and strings.xml files

Related Articles

Coding Tip: Using Custom Bindings for Property Editing in Sapphire
Creating Custom Editors in Sapphire

Let Us Hear from You!

If you have any comments or questions, we would love to hear from you @MyEclipseIDE on twitter or via the MyEclipse forum. Happy coding!