[Writer] Publipostage avec images

Vos meilleures macros et portions de code sont publiées dans cette section.
Aucun support sur une question de programmation ici !

Modérateur: Vilains modOOs

Règles du forum
Aucune question dans cette section !
Celle-ci rassemble les meilleures macros et portions de code. Vous pouvez en revanche commenter ou argumenter le code exposé. Vous pouvez même remercier l'auteur (cela fait toujours plaisir) en indiquant par exemple dans quel cadre ou contexte vous en avez eu l'utilité.
Si vous avez à poster quelque chose, faites-le depuis la section Macros et API et demandez à un modérateur de l'y déplacer.

[Writer] Publipostage avec images

Messagepar Pierre-Yves Samyn » 02 Jan 2008 16:15

Problématique : on dispose d'une table avec un champ contenant des Url pointant vers des images ; on souhaite réaliser un publipostage utilisant ce champ pour afficher l'image dans un contrôle Image.

Plusieurs approches sont possibles, notamment la décompression puis modification des fichiers XML constituant un document OpenOffice.

La bibliothèque jointe est un exemple (limité...) d'une autre solution réalisable par macro.

L'objectif n'est pas de recréer un assistant de publipostage mais de proposer un minimum de fonctionnalités, avec un minimum de contraintes de mise en oeuvre : la lettre-type doit simplement comprendre un contrôle image (Picto) de même nom que le champ comprenant l'url et le formulaire sous-jacent doit être fondé sur la même table.

Il ne s'agit donc pas ici d'une extension (la forme extension n'a été choisie que pour faciliter l'installation) et donc, volontairement, pas de commande de menu ajoutée, ni d'icône, etc.

Outre l'atteinte de l'objectif (créer un document de publipostage incluant les images), l'intérêt est ici pour moi de regrouper dans cette procédure quelques techniques "classiques" de manipulation des documents OpenOffice :

  • Création de document à partir d'un modèle
  • Navigation et écriture dans un document via les curseurs
  • Manipulation de formats
  • Manipulation de contrôles de formulaire
  • Manipulation de champs insérés dans le document
  • Manipulation de jeu de données (connexion, jeu d'enregisrements)

D'où la présentation de ce code dans la section "Suprême de code"...


Le document joint présente plus en détail l'installation, l'utilisation et les limitations.

Ces dernières pourraient bien entendu être levées... Encore une fois, l'objectif n'est pas de recréer un assistant "complet".

Par voie de conséquence il est inutile de poster pour demander l'évolution de ce code qui n'est qu'un exemple :D

La bibliothèque (télécharger)
Le document de présentation (télécharger)


Ci-dessous le code (mais il sera nécessaire de télécharger la bibliothèque pour disposer de la boîte de dialogue).
Code : Tout sélectionner   AgrandirRéduire
option explicit

global PysDlg as object, PysConnexion as object


Sub PysLancerPublipostage

dim PysLettreType as object, PysNewDoc as object, PysTexte as object, PysCurseur as object
dim PysForm as object, PysCtrlImg as object, PysTables as object
dim PysRowSet as object, PysEnum as object, PysChamp as object, PysRange as object


dim PysProp(0) as new com.sun.star.beans.PropertyValue

dim PysUrl as string
dim PysNbForms as integer

PysProp(0).name = "AsTemplate"
PysProp(0).value = true

PysLettreType = thiscomponent
PysUrl = PysLettreType.url

' Ne travaille que si le document a été enregistré (car on l'utilise par insertion > fichier)

if PysUrl <> "" and not(PysLettreType.isModified) then

' Création d'un nouveau document fondé sur la letre-type
   
   PysNewDoc = stardesktop.loadComponentFromUrl(PysUrl, "_blank", 0, PysProp())
   
' Chargement de la bibliotheque Tools car utilisation des fonctions IndexinArray et ToggleWindow
   GlobalScope.BasicLibraries.LoadLibrary("Tools")
   
   PysPatienter
   ToggleWindow false

' Ne travaille que si le document comprend un formulaire
   
   if PysNewDoc.DrawPage.Forms.count <> 0 then
      PysForm = PysNewDoc.DrawPage.Forms.getByIndex(0)

' Ne travaille que si le formulaire ne comprend qu'un seul contrôle (picto)   
      if PysForm.count = 1 then

' Accès à ce contrôle   
         PysCtrlImg = PysForm.getByIndex(0)

' On remonte du formulaire à la "connexion" utile pour :
' - créer le jeu d'enregistrements
' - accéder aux formats de données

         PysConnexion = PysForm.ActiveConnection
   
         if IsNull(PysConnexion) then
            MsgBox("Connexion impossible", 16)
         else
            PysTables = PysConnexion.Tables

' Ne travaille que si la source ne comprend qu'une table
            if PysTables.count = 1 then

' Création du jeu d'enregistrements correspondant   
               PysRowSet = createUnoService("com.sun.star.sdb.RowSet")
               with PysRowSet
                  .activeConnection = PysConnexion
                  .CommandType = "com.sun.star.sdb.CommandType.Table"
                  .Command = PysConnexion.Tables.getByIndex(0).Name               
                  .execute
               end with

' Utilise la fonction (Tools) pour tester si la source de données comprend
' un champ de même nom que le contrôle Image

               if IndexinArray(PysCtrlImg.name, PysRowSet.Columns.ElementNames) <> -1 then

' Toutes les conditions sont réunies, on peut "boucler" sur les enregistrements
   
                  with PysRowSet
                     .beforeFirst
                     PysNbForms = 0
                     while .next

' Pour le premier enregistrement, le document a déjà été créé, sinon
' on va à la fin du document, on insère un paragraphe avec saut de page
' puis on insère la lettre-type à la fin

                        if PysNbForms <> 0 then
                           PysTexte = PysNewDoc.text
                           PysCurseur = PysTexte.createTextCursor
                           PysCurseur.gotoEnd(False)
                           PysTexte.insertControlCharacter(PysCurseur, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, false)
                           PysCurseur.breakType = com.sun.star.style.BreakType.PAGE_BEFORE
                           PysCurseur.insertDocumentFromURL(PysUrl, array())
                           PysForm = PysNewDoc.DrawPage.Forms.getByIndex(PysNbForms)
                           PysCtrlImg = PysForm.getByIndex(0)
                        end if

' Assignation de l'url de l'image (contenue dans le champ de même nom dans la table)
                        PysCtrlImg.ImageUrl =  convertToUrl(.columns.getByName(PysCtrlImg.name).String)
                        PysNbForms = PysNbForms + 1
   
'Boucle sur les champs du document (et non de la source...)

                        PysEnum = PysNewDoc.TextFields.createEnumeration
' Tant qu'il y en a...
                        do while PysEnum.hasMoreElements
                           PysChamp = PysEnum.nextElement

' S'il s'agit d'un champ lié à la base de données
                           if PysChamp.supportsService("com.sun.star.text.TextField.Database") then

' Vérifie qu'il y a bien un champ du même nom
                              if IndexinArray(PysChamp.TextFieldMaster.DataColumnName, PysRowSet.Columns.ElementNames) <> -1 then
      
' Récupération de la position du champ dans le document
                                  PysRange=PysChamp.anchor.start

' Création d'un curseur d'écriture pour remplacer le champ par le texte contenu
' dans la base
                                  PysCurseur = PysRange.text.createTextCursorByRange(PysRange)

' Nécessaire de formater les champs Date ou Numérique
' avant d'écrire le contenu du champ
                                  select case .columns.getByName(PysChamp.TextFieldMaster.DataColumnName).TypeName
                                     case "DATE","DATETIME","TIME"
                                        PysCurseur.string =_
                                           PysFormat(.columns.getByName(PysChamp.TextFieldMaster.DataColumnName).String,_
                                                  .columns.getByName(PysChamp.TextFieldMaster.DataColumnName).FormatKey)
                                     case "DECIMAL","NUMERIC"
                                        PysCurseur.string =_
                                           PysFormat(val(.columns.getByName(PysChamp.TextFieldMaster.DataColumnName).String),_
                                                  .columns.getByName(PysChamp.TextFieldMaster.DataColumnName).FormatKey)
                                     case else
                                          PysCurseur.string =.columns.getByName(PysChamp.TextFieldMaster.DataColumnName).String
                                  end select

' Supprime le champ
                                 PysChamp.dispose
                              end if
                           end if
                        loop

' Met à jour la collection des champs du document
                        PysNewDoc.TextFields.refresh
                     wend
                     .dispose
                  end with
               else
                  MsgBox("Aucun champ nommé " & PysCtrlImg.name & " ne figure dans la source de données", 16)
               end if
            else
               MsgBox("Table non trouvée", 16)
            end if
         end if
      else
         MsgBox("Impossible de trouver le contrôle image dans le formulaire", 16)
      end if
   else
      MsgBox("Aucun formulaire n'a été trouvé", 16)
   end if
   
   ToggleWindow true
   PysFinPatienter
   msgbox "Terminé...", 64, "Publipostage"

else
   MsgBox("La lettre type doit avoir été enregistrée", 16)
end if

End Sub


sub PysPatienter

' Affiche un dialogue d'attente à l'utiliateur

dim  PysBibli as Object, PysMonDialog as object, PysControle as object
   DialogLibraries.LoadLibrary("PysPublipostage")
   PysBibli=DialogLibraries.GetByName("PysPublipostage")
   PysMonDialog=PysBibli.GetByName("PysDlgPatienter")
   PysDlg=CreateUnoDialog(PysMonDialog)
   PysDlg.setVisible(True)
   PysDlg.model.PysTextMsg.Text="Veuillez patienter..."

' Nécessaire pour laisser le temps à la connexion à la source de données de s'établir
   wait 20
end sub

sub PysFinPatienter
   PysDlg.setVisible(False)
   PysDlg.Dispose
end sub



function PysFormat(PysChamp, PysKey as long) as string

' A partir du numéro de format (PysKey) on recherche dans les formats, on obtient ainsi la chaîne représentant le format
' Par exemple : # ##0,00 [$€-40C];[RED]-# ##0,00 [$€-40C]
' Appel de la fonction Calc FORMAT (TEXT en GB) pour formater le contenu du champ avec ce format

' Nota : on ne peut utiliser la propriété NumberFormats de "thiscomponent" (la lettre-type) car les formats sont différents.
' On appelle donc logiquement le NumberFormatsSupplier de la "database" à laquelle on remonte via la Connexion.

dim PysService as object

PysService = CreateUnoService("com.sun.star.sheet.FunctionAccess")
PysFormat = PysService.callFunction("TEXT", array(PysChamp, PysConnexion.Parent.NumberFormatsSupplier.NumberFormats.getByKey(PysKey).FormatString))

end function

Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
 
Message(s) : 11276
Inscrit le : 02 Mai 2006 09:42

[Writer] Publipostage avec images (bis)

Messagepar Hubert Lambert » 23 Oct 2018 20:30

Bonjour,

Dans la suite logique de ce message, j’ai eu envie de généraliser la macro proposée pour la rendre utilisable quel que soit le type de document (étiquettes ou lettre), le type d’image, le nombre d’images par document, l’emplacement de l’image (cadre, tableau…), etc.

Comme je souhaiterais faire évoluer cette macro en fonction des besoins des utilisateurs, il me semble que la section Projets se prête mieux que la section Macros et API pour la publication du code. Mais libre aux modérateurs de déplacer le fil s’ils l’estiment utile.

Le "bis" du titre fait référence à la macro de Pierre-Yves Samyn citée dans le message précité, qui y propose une réécriture complète de la fusion de documents. Celle-ci propose une autre voie, qui "colle" au plus près du code existant (en l'occurrence le service MailMerge) et se focalise exclusivement sur l'intégration des images via une ébauche d'assistant.

Mode d’emploi
1. Dézipper les fichiers joints dans un même répertoire et les importer (Alt-F11 → Gérer → Bibliothèques → Importer et choisir le fichier "script.xlb").
2. Ouvrir un document modèle ou en créer un de manière classique; pour les images, insérer à l’endroit voulu un cadre qui ne contiendra que le champ correspondant à l’url.
3. Depuis le document modèle ouvert, exécuter la macro "publipostage_avec_images" (Alt-F11 → Mes Macros → PublipostageAvecImages → Module1 → Exécuter).
4. Choisir les enregistrements et les options, puis lancer.

Si aucun enregistrement n’est sélectionné, tous seront utilisés.
Le document modèle peut être créé à partir de l'assistant inclus dans la macro, par glisser-déposer des en-têtes de champs.
Les url des images peuvent être absolues ou relatives.

PublipostageAvecImages.png

Bugs connus
En raison du bug décrit ici, la sélection d’enregistrements est défaillante sous OpenOffice : il ne sera possible que de fusionner l’ensemble des éléments (sans sélection donc) ou un seul à la fois.

Cordialement.
Pièces jointes
PublipostageAvecImages.zip
v0.2
(4.23 Kio) Téléchargé 57 fois
AOOo 4.1.2 sur Win7
AOOo 4.1.x sur Linux Mint
LibreOffice 5.x/6.x sur Linux Mint
--
| « Nos défauts devraient nous donner une qualité : l'indulgence pour les défauts des autres » (Rivarol)
Avatar de l’utilisateur
Hubert Lambert
SuppOOrter
SuppOOrter
 
Message(s) : 1115
Inscrit le : 06 Avr 2016 08:26


Retour vers Suprême de code

Qui est en ligne ?

Utilisateur(s) parcourant ce forum : Aucun utilisateur inscrit et 1 invité