User guide - Design RTF model

Overview

To design your RTF model, you can use following RTF element :

  • merge fields (MERGEFIELD) to set the place where your data must be inserted in your RTf model after merge with JAVA context. You can customize and manage the style of your filed (bold, color,...)

    A merge field can be used too to insert an image (which could be generated) in your RTF model.

    name of your merge field must respect the name of your JAVA object and getters (your context).

  • bookmarks (BOOKMARK) are used to set start/end loop. A bookmark can be inserted anywhere in your RTF model (before/after a row of a table,...).
  • hyperlink fields (HYPERLINK) to manage hyperlink.
  • FormText fields (FORMTEXT) to manage form text where you can set a default value.

Design of your RTF model can be done with MS Word. Today it'snot possible to use OpenOffice. Click here for more d'informations.

Following sections describes rules to respect when you design your RTF model swith your JAVA context. Sections explains :

you can find samples of RTF model into rtftemplate-usecases-<version> distribution into the usecases/model folder. jakarta-velocity-model.rtf is the RTF model source which use the almost use case of RTFtemplate.

Samples describes below will use JAVA context composed by a liste of 2 developers. A developer has name. Here the code used when list is putted into the context :

  List developers = new ArrayList();
  Developer developer = new Developer();
  developer.setName("Developer 1");
  developers.add(developer);
  developer = new Developer();
  developer.setName("Developer 2");
  developers.add(developer);
  context.put("developers", developers );
        

Display simple value

POJO context

Simples values are designed with merge fields (MERGEFIELD) and hyperlink fields (HYPERLINK). You can apply on those RTF elements a style (Bold, Color,...) by using standard fonctionnality of your tool (MS Word,...).

ATTENTION when you apply a style on a field,you must select the whole of the field, otherwise you can have trouble after merging.

When you create a filed, use ABSOLUTELY fonctionnalities for create field (with MS Word or RTFTemplate.dot). Don't update the name of the field in the RTF model!!! Several people wrote me for trouble with RTFTemplate and their problem comming from taht.

Name of your field must respect a syntax. For instance to display the value of JAVA object Project :

  public class Project {

      private String name;
      
      public Project(String name) {
              this.name = name;
      }

      public String getName() {
              return name;
      }

      public void setName(String name) {
              this.name = name;
      }
  }

putted into context with key project :

context.put("project", new Project("Jakarta Velocity"));

name of the field must be nammed in your RTF model like this :

  $project.Name
  

Map context

You can use java.util.Map if you don't want use POJO object (works only with Velocity). Map key is the getter name, and Map value is the value getter. Project POJO sample can be done with Map like this :

  // Prepare Project context
  Map projectMap = new HashMap();  
  projectMap.put("Name", "Jakarta Velocity"); 

  // Put the Map into the context
  context.put("project", projectMap);

ATTENTION, it's important to respect the case in the key of the Map and the name of filed used into RTF model.

You can find samples here.

Format simple value

Display of simple value is done when JAVA object have getter type of :

It's possible to format value returned by getters by creating class which implement java.text.Format interface. Formatter class is linked to a class type.

For instance, to format all getters type of java.util.Date with dd/MM/yyyy pattern, you must set into rtftemplate instance with setDefaultFormat method, the formatter for java.util.Date class type like this :

  Format format = new SimpleDateFormat("dd/MM/yyyy");
  rtfTemplate.setDefaultFormat(java.util.Date.class, format);

By default RTFtemplate register formatters :

  • net.sourceforge.rtf.format.DefaultInputStreamFormat which format getters type of java.io.InputStream (which must return image stream) into hexadecimal code to insert image into RTF target model.
  • net.sourceforge.rtf.format.DefaultRTFCodeStringFormat which format getters type of net.sourceforge.rtf.format.rtfcode.RTFCodeString to transform (\n, \r) characters (\t) tabulation into RTF code.

IRTFCode interface

IRTFCode interface is particular RTFTemplate object type. Here IRTFCode signature :

  public interface IRTFCode {
    /**
     * Return true if content must be escaped 
     * (replace '{' character with "\{" and '}' with "\}") 
     * @return
     */
    public boolean isEscaped();
    
    /**
     * Return RTF content.
     * @return
     */
    public String getContent(); 
  }
  • getContent method must return String content of RTF code to display.
  • isEscaped> method must return true if RTF code content must be escaped and false otherwise. Escape characters means replace characters '{' and '}' by '\{'} and '\}'}. Indead if RTF target model contains a character '{' not closed with '}', MS Word will not able to open RTF model.

IRTFcode is used like JAVA primitif type into RTF model. If you put your IRTFCode object into context with myRTFCode key, you must call your merge field like this :

  $myRTFCode

and NOT like this :

  $myRTFCode.content 

RTFCodeString

By default RTFTemplate provides net.sourceforge.rtf.format.rtfcode.RTFCodeString class which implements IRTFcode. It is linked to net.sourceforge.rtf.format.DefaultRTFCodeStringFormat formatter. Here formatteur code :

package net.sourceforge.rtf.format;

import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;

import net.sourceforge.rtf.format.rtfcode.IRTFCode;
import net.sourceforge.rtf.util.StringUtils;

public class DefaultRTFCodeStringFormat extends Format {

  public StringBuffer format(Object obj, StringBuffer stringbuffer,
          FieldPosition fieldposition) {
    if (obj == null)
        return null;
    String content = null;
    if (obj instanceof IRTFCode)
        content = ((IRTFCode) obj).getContent();
    else if (obj instanceof String)
        content = (String) obj;
    if (content == null)
        return null;        
    // Replace \n\r with \\par
    String formattedContent = StringUtils.sub(content, "\n\r", "\\par ");
    // Replace \n with \\par
    formattedContent = StringUtils.sub(formattedContent, "\n", "\\par ");
    // Replace \t with \\tab
    formattedContent = StringUtils.sub(formattedContent, "\t", "\\tab ");
    return new StringBuffer(formattedContent);
  }

  public Object parseObject(String s, ParsePosition parseposition) {
    // Do nothing
    return null;
  }
}  

If your getter can return tabulation (\t), (\n,\r) you should use RTFCodeString in order to transform thoses characters into RTF code :

  • replace "\r\n" by \par.
  • replace "\n" by \par.
  • replace "\t" by \tab to manage tabulation.

If you put RTFCodeString instance into RTFTemplate context like this :

context.put("myRTFCode", new RTFCodeString("\n\n\t\r\nvalue\n\n"));

RTF code will be generated :

\par \par \tab \par value \par\par

to display tabulation,... correctly into your RTF model.

If your getter can return '{' or '}' character, you must escape it like this :

context.put("myRTFCode", new RTFCodeString("\n\n\t\r\nvalue\n\n{", true);

Manage loop

When you have data list, it's possible to display in your RTF model. Sometimes you want display your list into RTF table (which will generate sevenral rows), sometimes you want display your items of the list separated with , character.

Global rule

Loop are often managed with bookmarks (BOOKMARK). It exist some exception with RTF table.

The rule used by RTFtemplate is to iterate on the first field list type found after a start loop. A field is list type, if his JAVA object linked is stored into a JAVA list (java.util.Collection, java.util.List,...).

If you use RTFTemplate.dot, when you select a field, you can see if the field is type list or not. If field is list type, it must be included between start and end loop.

To set a start/end loop, you must create (except some exception) bookmarkes like this :

  • START_LOOP_{i} to set the start loop of ième iteration of your RTF model.
  • END_LOOP_{i} to set the end loop of ième iteration of your RTF model.

For isntance if you want display the list of develpers separated with , characters :

Developer 1, Developer 2,

RTF model must be designed like this :

 START_LOOP_1 $developers.Name , END_LOOP_1

Manage RTF table

Since 1.0.1-b10 version, the rule is NOT use start/end bookmarks to loop for rows of RTF table. RTFTemplate is able to detect RTF rows and iterate on the first field type of list found in the row of RTF Table.

You can find samples here.

If you use old version, you must distinguish following use cases.

RTF tables have some exceptions. Switch design of RTF table, start/end bookmarks are required or not.

Use case when bookmars must NOT be used.
  • use case 1 : your RTF table is composed with ONE row and your field (type list) is inserted into a cell of the row.
    ------------------------------------------------
    |$developers.Name                  |     |     |
    ------------------------------------------------
    

    After merge, the RTF target is :

    ------------------------------------------------
    |Developer 1                       |     |     |
    ------------------------------------------------
    |Developer 2                       |     |     |
    ------------------------------------------------
    
  • use case 2 : your RTF table is composed with header row WHICH HAVE A STYLE (ex : black color) and row which contains field (type list) :
    ------------------------------------------------
    |Header row  WHICH HAVE A STYLE    |     |     |
    ------------------------------------------------
    |$developers.Name                  |     |     |
    ------------------------------------------------
    

    After merge, the RTF target is :

    ------------------------------------------------
    |Header row  WHICH HAVE A STYLE    |     |     |
    ------------------------------------------------
    |Developer 1                       |     |     |
    ------------------------------------------------
    |Developer 2                       |     |     |
    ------------------------------------------------
    
Use case when bookmars must be used.

Since 1.0.1-b10 version, you can ignore this case.

When your RTF table is composed with header row WHICH HAVE NOT A STYLE and row which contains field (type list) :

------------------------------------------------
|Header row WHICH HAVE NOT A STYLE |     |     | START_LO0P_1 
------------------------------------------------
|$developers.Name                  |     |     | END_LO0P_1
------------------------------------------------

After merge, the RTF target is :

------------------------------------------------
|Header row WHICH HAVE NOT A STYLE |     |     |
------------------------------------------------
|Developer 1                       |     |     |
------------------------------------------------
|Developer 2                       |     |     |
------------------------------------------------
Another use cases.

Another use cases described below are sample to show what we can do with RTFTemplate :

  • use case 1 : when you want obtain this result :
    MyTitle
    ------------------------------------------------
    |Developer 1                       |     |     |
    ------------------------------------------------  
    
    MyTitle
    ------------------------------------------------
    |Developer 2                       |     |     |
    ------------------------------------------------  
    

    You must design your RTF model like this :

    START_LOOP_1
    
    MyTitle
    ------------------------------------------------
    |$developers.Name                  |     |     |
    ------------------------------------------------  
    
    END_LOOP_1
    
  • use case 2 : when you want obtain this result :
    ----------------------------------------------------------
    |Developer 1, Developer 2                    |     |     |
    ----------------------------------------------------------  
    

You must design your RTF model like this :

----------------------------------------------------------
| START_LOOP_1 $developers.Name , END_LOOP_1 |     |     |
---------------------------------------------------------- 

Manage images

With RTFTemplate you can insert images (which could be dynamicly generated) in your RTF model. To set the image in your RTF model, use a merge field. The JAVA object linked with the merge field must returns the InpuStream of the image to insert.

Image formats supported by RTFtemplate are PNG, JPG, EMF et BPM.

You can found samples with RTF model which manage images into rtftemplate-usecases-<version> distribution into the folder usecases/model/image. and JAVA classes into the package net.sourceforge.rtf.usecases.image.

Manage page break

With RTFTemplate it's possible to iterate on items of list and add a page break after each item. RTFTemplate don't generate a page break after the last item (to avoid to have a blank page).

To manage page break, you must design your RTF model like this :

  START_LOOP_1 (set at start of your RTF model)
  
  ....
   $developers.Name
  ....
  
  Page break
  
  END_LOOP_1

It's possible to group items of the list and generate a page break after each group. You can do that with JAVA code. For more information click here.

You can found samples with RTF model which manage page break into rtftemplate-usecases-<version> distribution into the folder usecases/model/page. and JAVA classes into the package net.sourceforge.rtf.usecases.page.

Manage user properties

With MS Word it's possible to create user properties. To do that, you must go to the menu File/Properties. In Customization tab, you can create your user properties (name, type, value).

You can manage user properties with RTFTemplatre like merge field :

  • if you want that RTFTemplate replace user property value/name with a value of your JAVA context, you must create a user property which respect the well syntax (like merge field) (eg : $myUserPropertyValue).
  • if you want manage list of user properties comming from the JAVA context, you must create a user property with name $myList.UserPropertyName and value $myList.UserPropertValue. JAVA context must contain a list with key myList which contain objects which have getters getUserPropertyName and getUserPropertyValue.

You can found samples with RTF model which manage images into rtftemplate-usecases-<version> distribution into the folder usecases/model/jakartavelocityproject. and JAVA classes into the package net.sourceforge.rtf.usecases.userproperties.