RSS Source Mapping

The UI Designer supports source generation and updating of Symbian resource (RSS) files, including LOC/Lxx/RLS localized string files and HRH headers shared between a class of C/C++ files. C++ files are handled by a one-way template expansion process. RSS files are handled by a two-way process using an RSS DOM. The <sourceMapping> element in a component definition file (.component) drives the process.

The source mapping engine maintains enough information to allow in-place modifications to RSS and related files. Also, it allows for user edits to be retained, as long as they are not also handled by the component.

General Concepts

Visualize RSS source mapping as walking down two parallel hierarchies. One is the hierarchy of component instances, properties, compound properties, arrays, and component reference properties. The other is the hierarchy of RSS RESOURCE definitions, field initializers, nested resource expressions, array initializers, and LLINK field initializers.

The hierarchies outlined here are not strictly parallel. For example, you may map something other than a component reference property to an LLINK field. If you map a compound property or another instance to an LLINK, the source mapping engine will take care of automatically generating a resource to satisfy the link. Conversely, a component reference property may be mapped to a resource expression; no standalone resource needs to exist in RSS.

At the leaf of the tree, where properties are mapped to field initializers, types needn't be mapped strictly. Usually, integer properties are mapped to WORD or BYTE RSS fields, but you may map enumerator properties or even literal text (corresponding to no property) to such fields as well.

XML elements in the <sourceMapping> element are driven from the RSS side of the picture (e.g. "map a resource", "map a field", etc.). The structure and nesting of these elements drive the structure of the generated RSS. Generally, a <mapResource...> element creates a new resource or resource expression, and <map...Member> elements map into a member or field initializer named by the "member" attribute.

The source mapping engine automatically generates names for resources which are guaranteed to be unique within the scope of a project and its designs. You may influence this only by supplying a fixed name for a resource using "rsrcName" in <mapResource>.

The "property" attribute inside the <map...Member> elements depicts how to walk the component instance and property hierarchy. This attribute specifies a "property path", which is a tiny language for navigating the data model.

For example, property="location.x" will read the "x" property inside the compound property named "location". The statement "holder.reference->value" will read the "value" property inside the "reference" component reference property inside the "holder" compound property. Usually a property attribute is a simple name. Note that you may target a compound property (e.g. "location") or a component instance (e.g. "holder.reference->") itself with a property path.

In both cases, the movement is one-way as nesting increases further into the RSS hierarchy or into the component instance hierarchy. The only way to go up the hierarchy is to map into an RSS LLINK field or read across a component reference property.

The following table lists supported mappings. See the following sections for details on the XML elements.

Supported Mappings
Mapping XML Element
Component instance <mapResource> <mapResourceMember>
<mapInstanceMember>
Compound property <mapResource> <mapResourceMember>
Simple leaf property <mapSimpleMember> <mapIdentifierMember>
<mapEnumMember>
Component reference property <mapReferenceMember> <mapInstanceMember>
<mapResourceMember>
Set of boolean properties <mapBitmaskMember>
Constant <mapFixedMember>


Mappings

Source mapping elements appear in the <sourceMapping> element of the component definition file.

Resource

The <mapResource> element defines a mapping from a property source to a resource. Attributes include:

Member Mappings

The following elements map individual properties to resource members:

Each element takes these attributes:

Examples of Property and Member mapping:

Given a current property source PS and a struct declaration STR:

Resource Member Mapping

Aside from property and member, the <mapResourceMember> element has the same syntax and semantics as the <mapResource> element. This element maps a compound property to a resource expression or statement. Mappings inside the element use the compound property as the property source. If the member is of STRUCT type, the mapping corresponds to that member. Otherwise, the member must be of LLINK type. In this case a uniquely-named resource holds the mapped data, which is referenced from the LLINK.

To map properties from the current property source into a STRUCT, use the property=“.” form and appropriate mapXYZMember. To map a compound property to members of the current resource, use the property=“bounds.width” form and appropriate mapXYZMember.

Example syntax:

<mapResourceMember property=... member=... struct=“...” headers=“...” >

Resource Generation Example:

myheader.rh file:

STRUCT RSRC {
 STRUCT  theStruct;
 WORD ckSum;
}
STRUCT FOO {
 BUF  buf;
 WORD  type;
 LONG count;
}

Component file:

<compoundPropertyDeclaration qualifiedName=“Foo">
  <property name=“text" type="localizedString" />
  <enumProperty name=“type" type=“..."  />
  <property name=“count" type=“integer“ />
</compoundPropertyDeclaration>
<properties>
  <property name="name" type="uniqueName"/>
  <compoundProperty name=“foo" type=“Foo"/>
  <property name=“checksum" type=“integer"/>
</properties>
<sourcemapping>
  <mapResource struct=“RSRC” headers=“myheader.rh”>
    <mapResourceMember property=“foo” member=“theStruct” struct=“FOO” headers=“myheader.rh” />
      <mapSimpleMember property=“text” member=“buf”/>
      <mapEnumMember property=“type” member=“type”/>
      <mapSimpleMember property=“count” member=“count”/>
    </mapResourceMember>
    <mapSimpleMember property=“checksum” member=“ckSum”/>
  </mapResource>
</sourcemapping>

Simple Member Mapping

The <mapSimpleMember> element is allowed within the mapResource, mapResourceElement, or mapResourceMember element. It is used to map a value to a struct member by specifying the property path that provides the value. For example:

<mapSimpleMember property="lineWidth" member="line_size"/>

This element allows you to map an integer, float, string, or reference members. Macros and localized strings are handled automatically. Anything in the data model can be represented in the resource file, and any form of string can be stored in the data model. There is no need for different actions based on the state of a string.

Component references are handled automatically. The resource for the target component instance is located or a stub resource is created. An error results under the following conditions:

Compound properties are mapped by using IPropertySource#getEditableValue().

Enum Member Mapping

The <mapEnumMember> element is allowed within the mapResource, mapResourceElement, or mapResourceMember element. It maps a given property with a resource member and converts enumerator names from one representation to another. This element may be used alone if proper style is followed. All the enumerator values in the data model should be the same as the value used in the resource (RSS) file. The “value” attributes under enumPropertyDeclaration should match the RSS enumerators. Otherwise, the enumerator mapping must be spelled out in subelements. Compound properties are mapped using IPropertySource#getEditableValue().

Attributes:

Example syntax:

<mapEnumMember property=... member=... [enumeration=“...” headers=“...”] [uniqueValue=“...” nameAlgorithm=“...”]> 

If the data model uses different enumerators than RSS, the <mapEnumMember> element must contain a list of <mapEnum value=... enum=... /> declarations.

Attributes:

Note that using the uniqueValue attribute does NOT force the use of this table. All possible enumerator values must be listed in <mapEnum> elements, otherwise a warning is emitted and no mapping is performed. The UI Designer will warn if a mapped enumerator cannot be resolved by means of headers (either those in <enumMemberMapping> or those brought in by surrounding <mapResource> elements).

Example:

<mapEnumMember property=“font” member=“fontName” header=“aknfonts.hrh”>
  <mapEnum value=“SYSTEM” enum=“EAknFontSystem”/>
  <mapEnum value=“TITLE” enum=“EAknFontTitle”/>
</mapEnumMember> 

Identifier Member Mapping

The <mapIdentifierMember> element maps a string property to an identifier in RSS. This places an unquoted string in RSS, as opposed to the <mapSimpleMember> element which always converts strings to literal string constants. Compound properties are mapped using IPropertySource#getEditableValue().

Example syntax:

<mapIdentifierMember property=“...” member=“...” />

Instance Mapping

The <mapInstanceMember> element maps an instance to an LLINK member or a STRUCT member of a resource. The <mapInstanceElement> does the same for array elements. This is rarely used but may be useful in a complex case of mapping selective elements of arrays, as follows:

<mapArrayMember property="." member="structs">
  <select attribute="is-emitted">
    <choice value="true">
      <mapInstanceElement />
    </choice>
    <choice />
  </select>
</mapArrayMember>

Reference Mapping

The <mapReferenceMember> and <mapReferenceElement> elements map a component reference property to an LLINK field in RSS. This will place the name of the generated resource for the referenced component instance into the field initializer in RSS.

Bitmask Mapping

The <mapBitmaskMember> and <mapBitmaskElement> elements are used to map a set of boolean properties to a single integer field in RSS. For example, the component may contain two boolean flags which are expressed as a logical OR of enumerators in RSS.

This mapping is powerful since it allows not only simple one-to-one mapping of properties to enumerators, but also allows groups of properties to be mapped to a single enumerator (e.g. "EAllFlags") and also allows a default value when no properties are set (e.g. "ENoFlags" or "EDefaultFlags").

First, this element has an "includedProperties" attribute specifying a space-separated list of properties which are involved in the mapping. This is used for two reasons:
(1) to allow you to map flags from a larger set of properties and
(2) to validate that you remembered to account for every combination of flags when mapping.

Generally, the latter constraint is not difficult to follow if you include one-to-one mappings for every flag property involved.

This element contains <mapBitmaskValue> elements that describe how a set of "true" properties can be mapped to an enumerator. For example: <mapBitmaskValue properties="myflag" value="EMyFlag" />
is a simple one-to-one mapping which maps "EMyFlag" if the "myflag" property is "true".

A more complex example is:
<mapBitmaskValue properties="part1Flag part2Flag" value="EPart1AndPart2Flag" />
which maps the "EPart1AndPart2Flag" only if both "part1Flag" and "part2Flag" are "true".

The <mapBitmaskValue> elements are iterated in order until all the "includedProperties" have been accounted for. Thus, specify the more complex mappings first, and then the one-to-one mappings, and finally an empty mapping, which is used only if no properties have been found to be "true". For example:

<mapBitmaskMember property="flagSet" member="flags"
   includedProperties="allowEdit allowCursorMovement compatibility">
   <mapBitmaskValue properties="allowEdit allowCursorMovement" value="EFullEditing" />
   <mapBitmaskValue properties="allowEdit " value="EAllowEditing" />
   <mapBitmaskValue properties="allowCursorMovement" value="EAllowCursorMovement" />
   <mapBitmaskValue properties="compatibility" value="ECompatibilitySetting" />
   <mapBitmaskValue properties="" value="ENoFlags" />
 </mapBitmaskMember>

In a model, if both "allowEdit" and "allowCursorMovement" are "true", but "compatibility" is false, then the RSS initializer generated would be:

 flags = EFullEditing;

If "allowEdit" is "true" and "compatibility" is true, then the initializer would be:

 flags = EAllowEditing | ECompatibilitySetting;

If none of these properties is true, then the initializer would be:

 flags = ENoFlags;

Array Member Mapping

The <mapArrayMember> element maps a sequence to an array-typed member of a struct. It contains one subelement to describe how to map each array element.

The < mapArrayElement> is not allowed in RSS. Syntax and semantics mirror those of mapXYZMember, except no member/property attributes are provided. Element mapping uses the current element as the property source. Do not use this to map non-sequence properties to RSS array elements. Use the member=“field[index]” syntax and the appropriate mapXYZMember.

Array Member Mapping Example:

RSS file:

STRUCT NUMBER_LIST { 	WORD items[]; }

Component file:

<arrayProperty name=“itemList” type=“integer”/>
<sourceMapping>
  <mapResource struct=“NUMBER_LIST” header=“...”>
    <mapArrayMember property=“itemList” member=“items”>
      <mapSimpleElement/>
    </mapArrayMember>
  </mapResource>
</sourceMapping>

Fixed Mapping

This mapping maps a constant value to a member or array element. It is used strictly to override the default value specified in RSS.

No "property" attribute is provided. Instead, set the "value" attribute to the literal text to inject into the initializer. This is not type-checked in any way.

Type Mapping

Some mappings are quite lengthy and completely associated with a given compound type. Instead of repeatedly specifying the mapping rules for every use of the property (in different components or in different conditions), you may place the type's source mapping inside the <compoundPropertyDeclaration> element and invoke it with the <mapMemberFromType> and <mapElementFromType> elements.

Place a <sourceTypeMapping> element in <compoundPropertyDeclaration> to associate mappings with the compound type. The only difference from normal RSS source mapping is, the top-level element is a <map...Type> element, which is just like <map...Member> or <map...Element> except that no specific member or array element is implied. For example:

<compoundPropertyDeclaration qualifiedName="com.nokia.test.TRgb">
   <property name="r" type="integer"/>
   <property name="g" type="integer"/>
   <property name="b" type="integer"/>
   <sourceTypeMapping>
     <mapResourceType struct="RGB" headers="basicheader.rh" >
       <mapSimpleMember property="r" member="r" />
       <mapSimpleMember property="g" member="g" />
       <mapSimpleMember property="b" member="b" />
     </mapResourceType>
   </sourceTypeMapping>
</compoundPropertyDeclaration>
 

When mapping this type, simply reference the property that uses the type, in <mapMemberFromType> or <mapElementFromType>. For example, assuming the "colors" property is of type "com.nokia.test.TRgb", then this will map its elements to a new RGB resource expression in the member "colors":

 <mapMemberFromType property="colors" member="colors" />

A compound type may map to more than one pattern in RSS. In such a case, specify multiple <map...Type> elements in the type declaration, and give each a unique "typeId" attribute. Specify the same "typeId" attribute in the <mapMemberFromType> or <mapElementFromType> mappings. If typeId is missing from both the type declaration or the mapping, this mapping matches.

Conditional Mapping

In some cases, property values require a component to be mapped in a different way. An enumeration may indicate use of a built-in resource or a flag may indicate another property is ignored. Such a model makes two-way mapping more difficult. A point of selection should resolve to mutually exclusive states in the data model and RSS. Thus, conditional generation must work on the basis of equality and simple property values.

The <select property=“...”> element encloses a set of alternate mapping groups. The "property" attribute is a path to a property of interest (such as, name or struct.member). The <choice [value=“...”]> element encloses a set of mapping elements. The "value" attribute is the value to compare with the property value. If unspecified, it acts as the “default”. The first matching <choice> is applied and all others ignored. The <select> element can appear inside <sourceMapping> and <mapResource*> elements.

A <select> operation may test whether an instance of a given component type exists in a component. The value of the match is non-empty if an instance of the type is found, otherwise it is empty, so structure the comparison in a negative fashion where a valueless choice always matches. For example:

<select property="[com.nokia.sdt.series60.MenuPane]">
 <choice value=“”>
  <!-- no match -->
 </choice>
 <choice>
  <!-- default match -->
 </choice>

General node paths can be used here, including parent navigation. For example:

<select property=“[parent].isEnabled”>
 <choice value=“true”>
...

A <select> operation may be made against attribute values. For example:

<select attribute="is-dialog-content">
 <choice value=“true”>
... </choice> <choice>
... </choice> </select>

A <select> operation may test the length of an array (empty vs. non-empty) to avoid emitting illegal resources (CAknPopupFieldText.component). For example:

<select property="items">
 <choice value="0">
  <!-- don't emit for 0 items: this causes a panic -->
 </choice>
 <choice>
  <mapResourceMember ...>
 </choice>
</select> 

A <select> operation may also match the existence of a property, which matters, for instance, to tell if a given property extender has supplied it. For example:

<select propertyExists="foo.bar">
   <choice value="true">
   ...
   </choice>
   <choice/>
</select>

A <select> operation may also check whether the current component instance is derived from a certain type. Obviously, a component knows its own type, but this is useful for checking component references or children in an array mapping. For example:

<mapArrayMember>
   <select isComponentInstanceOf="com.nokia.test.ArrayChildItem">
     <choice value="true">
     ...
     </choice>
     <choice/>
   </select>
</mapArrayMember>

Following is an example of generating a control button in a top level component.

Section of a component definition file:

<compoundPropertyDeclaration qualifiedName="com.nokia.sdt.series60.CBAProperty">
 <property name="leftText" type="localizedString" />
 <enumProperty name="leftId" type=“..." />
</compoundPropertyDeclaration>

<properties> <property category="Basic" name="name" type="uniqueName"/> <compoundProperty name="CBA" type="com.nokia.sdt.series60.CBAProperty"/> </properties>

Section of a resource file:

STRUCT CBA {
 STRUCT buttons[];  // of CBA_BUTTON
}

STRUCT CBA_BUTTON { WORD id;
BUF txt; }

Section of a component definition file:

<sourcemapping>
  <select property=“CBA”>
    <choice value=“CUSTOM”>
      <mapResource struct=“CBA” headers=“...”>
        <mapResourceMember property=“CBA” member=“buttons[0]”  struct=“CBA_BUTTON” headers=“...”>
          <mapEnumMember property=“leftId” member=“id” uniqueValue=“UNIQUE” />
          <mapSimpleMember property=“leftText” member=“txt”/>
        </mapResourceMember>
      </mapResource>
    </choice>
    <choice>
      <mapSimpleMember property=“CBA” member=“cba” />
    </choice> <!-- here, the value of CBA should be the same as the resource name -->
  </select>
</sourcemapping>