Guide utilisateur - Désigner modèle RTF

Préambule

Pour désigner votre modèle RTF, vous pouvez utiliser les élements RTF suivant :

  • les champs de fusions (MERGEFIELD) qui permettent d'indiquer l'endroit ou votre donnée doit être insérée dans votre modèle RTF après fusion avec le contexte. Vous pouvez ainsi gérer la police,la mise en gras,.. à utiliser pour mettre en forme votre donnée lors du désign de votre modèle RTF.

    Un champs de fusion peut être aussi utilisé pour insérer une image (qui pourrait être généré dynamiquement) dans votre modèle.

    Le nom du champs de fusion doit respecter le nom de votre objet JAVA et de ses getters (votre contexte).

  • les signets (BOOKMARK) qui sont utilisés pour indiquer un début/fin de boucle. Un signet à la différence d'un champs de fusion peut être inséré n'importe où dans votre modèle RTF (avant/après une ligne d'un tableau,...). Le seul inconvéniant est qu'il est assez difficile de le détecter visuellement dans votre modèle.
  • les champs hypertextes (HYPERLINK) qui permettent de gérer des liens hyper textes.
  • les champs FormText (FORMTEXT) qui permettent de gérer les formulaire texte où il est possible de mettre une valeur par défaut.

Le design de votre modèle RTF peut s'effectuer à l'aide de MS Word. Concernant OpenOffice, il n'est pas possible de l'utiliser aujourd'hui, cliquer ici pour plus d'informations.

Les sections suivantes décrivent les règles à utiliser pour modéliser votre modèle RTF en fonction de votre contexte JAVA. Elles expliquent :

Vous pouvez trouver des exemples de modèles RTF dans la distribution rtftemplate-usecases-<version> dans le répertoire usecases/model. Le modèle RTF qui répertorie la plupart des cas d'utilisation de RTFTemplate est jakarta-velocity-model.rtf

Les exemples décrits ci dessous s'appuieront sur le contexte d'une liste de deux développeurs. Un développeur a un nom. Voici le code utilisé lorsque cette liste sera posé dans le contexte :

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

Afficher une valeur simple

Contexte POJO

Les valeurs simples sont désignées par les champs de fusions (MERGEFIELD) et les champs liens hyper textes (HYPERLINK). Vous pouvez appliquer sur ces élements RTF un style (Gras, Couleur, Police,...) en utilisant les fonctionnalités standards de votre outil de modélisation (MS Word,...).

ATTENTION lorsque vous appliquez un style sur un de vos champs, faites attention à sélectionner le champs en entier, sinon vous risquez de rencontrer des problèmes lors de la fusion.

Lorsque vous créer un champs, utilisez ABSOLUMENT les fonctionnalités de création d'un champs fourni par MS Word ou par la macro RTFTemplate.dot. Ne vous amusez pas à modifier le nom dans le modèle RTF!!! Je me permets d'insister sur ce point car j'ai eu plusieurs personnes qui m'ont contacté et qui ont eu des soucis avec RTFTemplate. Leur problème venait de là.

Le nom de votre champs doit respecter une certaine syntaxe. Par exemple, pour afficher la valeur de l'objet JAVA 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;
      }
  }

mis dans le contexte avec la clé project :

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

le nom du champs doit être nommé ainsi dans votre modèle RTF :

  $project.Name
  

Contexte Map

Il est aussi possible d'utiliser une java.util.Map si vous ne voulez pas créer d'objets POJO (fonctionne uniquement avec Velocity). La clé de la Map correspond au nom du getter, et la valeur de la Map à la valeur du getter. L'exemple ci-dessus peut être effectué à l'aide d'une Map comme ceci :

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

  // Met la Map dans le contexte
  context.put("project", projectMap);

ATTENTION, il est important de respecter la casse dans la clé de la Map et dans le nom du champs utilisé dans votre modèle RTF.

Vous pouvez trouver des examples ici.

Formatter une valeur simple

L'affichage d'une valeur simple d'un objet s'effectue lorsque l'objet JAVA a un getter de type :

Il est possible de formatter la valeur retournée par un de ces types de getters à l'aide d'une classe formateur qui implémente l'interface java.text.Format. Un formatteur est associé à un type de classe.

Par exemple pour formatter tous les getters de type java.util.Date dans le pattern spécifique dd/MM/yyyy, vous devez enregistrer dans l'instance rtftemplate à l'aide de la méthode setDefaultFormat, le formatteur pour le type java.util.Date comme ceci :

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

Par défaut RTFtemplate enregistre les formatteurs :

  • net.sourceforge.rtf.format.DefaultInputStreamFormat qui permet de formatter les getters de type java.io.InputStream (qui doivent retourner un flux d'une image) en code hexadécimal pour insérer l'image dans le modèle cible RTF.
  • net.sourceforge.rtf.format.DefaultRTFCodeStringFormat qui permet de formatter les getters de type net.sourceforge.rtf.format.rtfcode.RTFCodeString pour transformer les retours à la ligne (\n, \r) et les tabulations (\t) en code RTF.

Interface IRTFCode

L'interface IRTFCode est un type d'objet particulier de RTFTemplate. Voici sa 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(); 
  }
  • la méthode getContent doit retourner le contenu String du code RTF à afficher.
  • la méthode isEscaped doit retourner true si le code RTF de content doit être échapé et false sinon. Echaper le code RTF signifie que les caractères '{' et '}' doivent être remplacé par '\{' et '\}'. En effet si le document RTF cible contient par exemple un caractère '{' non fermé par '}', MS Word sera incapable d'ouvrir le document.

IRTFcode se distingue aussi des autres types (non primitifs) par son utilisation dans le modèle RTF. Elle se comporte comme un type primitif, autrement dit si vous posez votre objet de type IRTFCode dans le contexte avec la clé myRTFCode, vous devez nommez votre champs de fusion comme ceci :

  $myRTFCode

et pas comme on pourrait le croire

  $myRTFCode.content 

RTFCodeString

RTFTemplate fournit par défaut net.sourceforge.rtf.format.rtfcode.RTFCodeString, une implémentation de IRTFcode, qui est associée au formatteur net.sourceforge.rtf.format.DefaultRTFCodeStringFormat. Voici le code du formatteur :

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

Si votre getter est susceptible de contenir des retour à la ligne, des tabulations, RTFCodeString vous permettra de les interpréter dans votre modèle RTF, autrement dit :

  • remplace la chaîne "\r\n" par \par pour gérer les retours à la ligne.
  • remplace la chaîne "\n" par \par pour gérer les retours à la ligne.
  • remplace la chaîne "\t" par \tab pour gérer les tabulations.

Si vous enregistrez dans le contexte RTFtemplate, une instance RTFCodeString comme ceci :

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

ceci génerera le code RTF suivant :

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

pour afficher les retours à la lignes et les tabulations correctement dans votre modèle RTF.

Si vous êtes susceptibles d'avoir des caractères '{' ou '}' vous pouvez les échaper comme ceci :

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

Gestion des boucles

Lorsque vous avez une liste de données, il est possible de les afficher dans votre modèle RTF. Parfois vous voulez afficher votre liste dans un tableau RTF (qui générera plusieurs lignes), parfois vous voulez afficher votre liste d'items séparés par des ,.

Règle générale

En règle générale, les boucles sont gérés par les signets (BOOKMARK). Il existe certaines exception concernant les tableaux RTF.

La règle utilisé par RTFTemplate est d'itérer sur le premier champs de type list, détecté après un début de boucle. Un champs est de type list, si son objet JAVA associé est stocké dans une liste JAVA (java.util.Collection, java.util.List,...).

Si vous utilisez la macro RTFTemplate.dot fourni par RTFTemplate, lorsque vous sélectionner un champs, une indication type list s'affiche. Si le champs est de type list, il doit OBLIGATOIREMENT être inséré entre un début/fin de boucle.

Pour indiquer un début/fin de boucle, vous devez créer (sauf exception) les signets suivants :

  • START_LOOP_{i} pour indiquer le début de la ième iteration de votre modèle.
  • END_LOOP_{i} pour indiquer la fin de la ième iteration de votre modèle.

Par exemple si on souhaite afficher la liste des développeurs séparés par le caractère , :

Developer 1, Developer 2,

le modèle RTF doit être désigné de la façon suivante :

 START_LOOP_1 $developers.Name , END_LOOP_1

Gestion des tableaux

Depuis la version 1.0.1-b10 la règle est de ne plus utiliser de signets début/fin boucle pour itérer sur les lignes d'un tableau. RTFTemplate est capable de detecter les lignes RTF et d'itérer sur le premier champs de type liste trouvé dans la ligne du tableau.

Vous pouvez trouver des examples ici.

Si vous utilisez une version antérieur à 1.0.1-b10, vous devez distinguer les cas suivants.

Les tableaux RTF sont un cas à part. En effet selon le tableau que vous désigner, les signets début/fin boucle doivent ou ne doivent pas être utilisés.

Cas où les signets NE doivent PAS être utilisés.
  • cas 1 : votre tableau est constitué d'UNE seule ligne et votre champs de type liste est inséré dans une cellule de la ligne.
    ------------------------------------------------
    |$developers.Name                  |     |     |
    ------------------------------------------------
    

    Après fusion, on obtient :

    ------------------------------------------------
    |Developer 1                       |     |     |
    ------------------------------------------------
    |Developer 2                       |     |     |
    ------------------------------------------------
    
  • cas 2 : votre tableau est constitué d'une ligne header QUI A UN STYLE (ex : couleur noir) et d'une ligne qui contient le champs de type liste :
    ------------------------------------------------
    |Ligne Header QUI A UN STYLE       |     |     |
    ------------------------------------------------
    |$developers.Name                  |     |     |
    ------------------------------------------------
    

    Après fusion, on obtient :

    ------------------------------------------------
    |Ligne Header QUI A UN STYLE       |     |     |
    ------------------------------------------------
    |Developer 1                       |     |     |
    ------------------------------------------------
    |Developer 2                       |     |     |
    ------------------------------------------------
    
Cas où les signets doivent être utilisés.

Depuis la version 1.0.1-b10, vous pouvez faire abstraction de cas.

Celui-ci est un cas d'exception. Il ressemble tres fortement au dernier cas. Le tableau est constitué d'une ligne header QUI N'A PAS DE STYLE et d'une ligne qui contient le champs de type liste :

------------------------------------------------
|Ligne Header QUI N'A PAS DE STYLE |     |     | START_LO0P_1 
------------------------------------------------
|$developers.Name                  |     |     | END_LO0P_1
------------------------------------------------

Après fusion, on obtient :

------------------------------------------------
|Ligne Header QUI N'A PAS DE STYLE |     |     |
------------------------------------------------
|Developer 1                       |     |     |
------------------------------------------------
|Developer 2                       |     |     |
------------------------------------------------
Autres cas.

Les autres cas décrits ci dessous, sont à titre d'exemples de ce que l'on peut faire avec RTFTemplate.

  • cas 1 : lorsque vous voulez obtenir ce type d'affichage :
    MyTitle
    ------------------------------------------------
    |Developer 1                       |     |     |
    ------------------------------------------------  
    
    MyTitle
    ------------------------------------------------
    |Developer 2                       |     |     |
    ------------------------------------------------  
    

    Vous devez désigner votre modèle RTF de la façon suivante :

    START_LOOP_1
    
    MyTitle
    ------------------------------------------------
    |$developers.Name                  |     |     |
    ------------------------------------------------  
    
    END_LOOP_1
    
  • cas 2 : lorsque vous voulez obtenir ce type d'affichage :
    ----------------------------------------------------------
    |Developer 1, Developer 2                    |     |     |
    ----------------------------------------------------------  
    

    Vous devez désigner votre modèle RTF de la façon suivante :

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

Gestion des images

RTFTemplate permet d'insérer des images (qui pourraient être générées dynamiquement) dans votre modèle RTF. Pour placer l'image dans votre modèle, utilisez un champs de fusion comme si vous voulez afficher une valeur simple. Il suffit que l'objet JAVA associé à ce champs de fusion retourne un InpuStream qui contient le flux de l'image à insérer.

Les formats d'images supportés par RTFTemplate sont PNG, JPG, EMF et BPM.

Vous pouvez trouver des exemple de modèles RTF qui gère les images dans la distribution rtftemplate-usecases-<version> dans le répertoire usecases/model/image. Les classes JAVA associées à ce modèles se trouvent dans le package net.sourceforge.rtf.usecases.image.

Gestion des sauts de pages

Avec RTFTemplate il est possible d'itérer sur une liste d'items et d'ajouter un saut de page après chaque item. RTFTemplate ne génera pas de saut de page après le dernier item (pour éviter d'avoir une page blanche).

Pour gérer les sauts de pages, vous devez modéliser votre modèle RTF comme ceci :

  START_LOOP_1 (placé au début du modèle RTF)
  
  ....
   $developers.Name
  ....
  
  Saut de page 
  
  END_LOOP_1

Il est aussi possible de grouper les items de la liste et de générer un saut de page après chaque groupe. Ceci s'effectue programmatiquement. Pour plus d'information cliquez ici.

Vous pouvez trouver des exemple de modèles RTF qui gère les sauts de pages dans la distribution rtftemplate-usecases-<version> dans le répertoire usecases/model/page. Les classes JAVA associées à ce modèles se trouvent dans le package net.sourceforge.rtf.usecases.page.

Gestion des propriétés utilisateurs

Avec MS Word, il est possible de créer des propriétés utilisateurs. Pour effectuer ceci, accédez au menu Fichier/Propriétés. Dans l'onglet Personnalisation, vous pouvez créer vos propriétés utilisateurs (nom, type et valeur).

Vous pouvez gérer ces propriétés avec RTFtemplate comme si vous gérer un champs de fusion :

  • si vous voulez que RTFTemplate remplace la propriété valeur/nom par une valeur provenant du contexte, vous devez créer une propriété utilisateur qui respecte la bonne syntaxe (comme un champs de fusion) (eg : $myUserPropertyValue).
  • si vous voulez gérer une liste de propriété utilisateurs (provenant du contexte), vous devez créer une propriété utilisateur avec le nom $myList.UserPropertyName et la valeur $myList.UserPropertValue. Le contexte JAVA doit ensuite contenir une liste de clé myList qui contient des objets qui ont les getters getUserPropertyName et getUserPropertyValue.

Vous pouvez trouver des exemple de modèles RTF qui gère les sauts de pages dans la distribution rtftemplate-usecases-<version> dans le répertoire usecases/model/jakartavelocityproject. Les classes JAVA associées à ce modèles se trouvent dans le package net.sourceforge.rtf.usecases.userproperties.