Version Anglaise / English version
Une version anglaise de cette FAQ existe à l'adresse suivante : https://portal.hardis-group.com/x/-wkbIQ
An english version of this FAQ exists à the following address : https://portal.hardis-group.com/x/-wkbIQ
Aide
pour accéder à l'aide en ligne adelia, on peu accéder à l'aide d'un navigateur à l'adresse suivante :
Plus précisément on pourra accéder directement aux :
- Ordres L4G (ou par thème )
- Objets graphiques
- Fonctions prédéfinies (ou par thème)
- Mots réservés
- Fonctions de la VaToolBx (ou par thème)
Raccourcis
CTRL+D | Envoie vers le paragraphe de déclaration le plus proche. |
CTRL+SHIFT+D | Envoie vers le paragraphe de déclaration du programme. En pressant CTRL+SHIFT+D de nouveau on revient au point de départ inital. |
CTRL+SHIFT+I | Indente le code source séléctionné ( ne pas indenter si possible tout le source car cela perd les alignements manuel effectués sur les codes qui occupent plusieurs lignes (avec le caractère de continuation "-") |
CTRL+ALT+S | Affecte le serveur logique par défaut aux lignes sélectionnées. |
CTRL+ALT+L | Remet côté client les lignes sélectionnées (à l'opposé du CTRL+ALT+S ) |
CTRL+SHIFT+F | Ouvre l'outil de recherche multi source. |
CTRL+SHIFT+V | Démarre la vérification interactive du code Adelia. |
CTRL+SHIFT+G | Lance la génération du programme (soumet un travail dans le gestionnaire de travaux Adelia) |
CTRL+F | Ouvir l'outil de recherche de texte |
CTRL+F3 | Recherche le texte sélectionné dans le code en cours d'édition. |
F3 | Affiche la prochaine ligne de code contenant le texte recherché. |
SHIFT+F3 | Affiche la ligne de code précédente contenant le texte recherché. |
F8 | Affiche la prochaine ligne de code ayant une erreur détectée par la vérification interactive Adelia. |
SHIFT+F8 | Affiche la ligne de code précédente ayant une erreur détectée par la vérification interactive Adelia. |
CTRL+F7 F7 | Crée ou enlève un signet |
ALT+DOWN | Quand le curseur est positionné sur une variable ou un objet, cette séquence permet d'accéder à la ligne de déclaration de l'objet. |
Ne pas indenter tout le source (CTRL+SHIFT+S) car cela perdrait les alignements manuels.
Declarations
1 - Déclarations par référence
Pour déclarer des variables il vaut mieux faire des déclarations en référence à une autre variable ou à une propriété (du MLD). Si l'entité n'est pas utilisée dans le programme, vous pouvez aussi indiquer à quelle entité appartient la propriété dans l'ordre REF.
Pour declarer des listes il vaut mieux faire référence à une entité (1 ou plusieurs entités si nécessaire).
/* ___ Déclarations des variables _______________________________________________________ REF(A5_COD_ARTICLE) w_COD_ARTICLE_1 /* définir la variable w_COD_ARTICLE_1 de la même façon que la propriété A5_COD_ARTICLE REF(A5_COD_ARTICLE HL_ART_ALCOOL) w_COD_ARTICLE_2 /* définir la variable w_COD_ARTICLE_2 de la même façon que la propriété A5_COD_ARTICLE de l'entité HL_ART_ALCOOL REF(w_COD_ARTICLE_2) w_COD_ARTICLE_3 /* définir la variable w_COD_ARTICLE_3 de la même façon que la variable w_COD_ARTICLE_2 /* ___ Déclarations des listes __________________________________________________________ LISTE LST_ART_ALC_1 *REF_MLD(HL_ART_ALCOOL) /* définir une liste avec toutes les propriétés de l'entité HL_ART_ALCOOL LISTE LST_ART_ALC_2 *REF_MLD(HL_ART_ALCOOL) *REF_MLD(HL_ART_LANGUE) /* définir une liste avec toutes les propriétés des entités HL_ART_ALCOOL et HL_ART_LANGUE LISTE LST_ART_ALC_3 *REF_MLD(HL_ART_ALCOOL) *REF_MLD(HL_ART_LANGUE) w_COD_ARTICLE_1 /* définir une liste avec toutes les propriétés des entités HL_ART_ALCOOL et HL_ART_LANGUE et également la variable w_COD_ARTICLE_1
2 - Taille des variables
1 - Variables ALPHA
Les variables de type Alpha peuvent avoir une taille comprise entre 1 et 8386552 .
La taille de la variable peut aussi indiquée en :
- kilobytes (* 1024) en ajoutant le suffixe "K" à la valeur (jusqu'à 8189K), ou bien
- megabytes (* 1048576) en ajoutant le suffixe "M" à la valeur (jusqu'à 7M)
Attention
/* ___ Déclarations des variables _______________________________________________________ ALPHA( 35) MyVariable1 ALPHA( 2205) MyVariable2 ALPHA( 5K) MyVariable3 ALPHA( 7M) MyVariable4
2 - Variables NUM_E
Les variables de type NUM_E sont définies par la taille Totale de la variable et le nombre de décimales : NUM_E(NombreDeChiffresAuTotal, nombreDeDécimales)
La taille totale de la variable numérique doit être comprise entre 1 et 63 .
La taille correspond au nombre total de chiffres (décimales comprises).
La valeur décimale est incluse dans le nombre total de chiffres.
Comme le nombre de décimales est inclus dans le nombre total de chiffre, le nombre de décimales sera inférieur ou égal au nombre total de chiffres.
Attention
/* ___ Déclarations des variables _______________________________________________________ NUM_E( 8,0) MyNum1 /* 8 chiffres, 8 pour la partie entière, 0 pour la partie décimale NUM_E( 15,3) MyNum2 /* 15 chiffres, 12 pour la partie entière, 3 pour la partie décimale NUM_E( 5,5) MyNum3 /* 5 chiffres, 0 pour la partie entière, 5 pour la partie décimale
Constantes
Les constantes sont utilisées pour remplacer une valeur "en dur".
Une constante peut être utilisée pour afficher un valeur texte, un code action, un code retour, etc.
1 - Définition
Pour définir une nouvelle constante, il suffiit d'aller dans menu Référentiel de l'éditeur L4G, séléctionner la ligne de menu Dictionnaire des constantes (ou bien d'appuyer sur F9).
- Le nom doit être représentatif de la valeur de la constante,
- la valeur est ce qui va remplacer la constante dans le code,
- la case à cocher "Constante traduisible" est à cocher pour les textes dont on voudra qu'ils soient extraits par le gestionnaire de traduction (par exemple pour les constantes textes affichées dans un écran)
2 - Utilisation
Exemples d'utilisations des constantes :
/* ___ Code sans constantes _____________________________________________________________ si codeAction = 'CR' btn_action:texte = 'Créer' sinon btn_action:texte = 'Modifier' fin ... returnCode = 'EX' /* ___ Code avec constantes _____________________________________________________________ si codeAction = _ACTION_CREATION btn_action:texte = _TEXT_CREATE sinon btn_action:texte = _TEXT_MODIFY fin ... returnCode = _RETURN_EXIT
Valeurs numeriques
1 - Valeurs arrondies
Pour effectuer un calcul avec une valeur arrondie, on utilisera la lettre H juste avant le signe =.
Sans l'opérateur H, le résultat serait tronqué.
La lettre H correspond à "Half adjustment" .
Les resultats compris entre 0 et 0.49 seront arrondis à 0, les resultats compris entre 0.50 et 0.99 seront arrondis à 1.
/* ___ Déclarations _____________________________________________________________________ NUM_E( 3,0) x NUM_E( 3,0) y /* ___ Code _____________________________________________________________________________ x = 2 / 3 /* x contiendra 0 y H= 2 / 3 /* y contiendra 1
2 - Calcul du reste
Pour récupérer le reste d'une division, on peut utiliser l'ordre L4G reste.
Cette ordre L4G doit être utilisé immédiatement après l'ordre de division.
Tip :
La Fonction prédéfinie Modulo peut maintenant être utilisée à la place de l'instruction L4G reste !
/* ___ Déclarations _____________________________________________________________________ NUM_E( 3,0) x NUM_E( 3,0) y /* ___ Code _____________________________________________________________________________ x = 10 / 3 /* x contiendra la valeur 3 reste y /* y contiendra la valeur 1
3 - Calcul du Modulo
Pour calculer le modulo entre un numérateur et un dénominateur, on peut maintenant utiliser la fonction prédéfinie &modulo.
Cette fonction prédéfinie peut être utiilisée à la place lde l'instruction L4G reste.
/* ___ Déclarations _____________________________________________________________________ NUM_E( 3,0) x NUM_E( 3,0) y /* ___ Code _____________________________________________________________________________ x = 10 /* x contiendra la valeur 3 y = &modulo(x;3) /* y contiendra la valeur 1
Squellette Adelia
1 - Programmes Visual
Un programme visual est constitué d'un certain nombre de paragraphes :
- DECL PGM. Dans ce paragraphe, on déclare les variables globales (ou paramètres, listes, curseurs etc) du programme,
- INIT PGM. C'est le point d'entrée du programme,
- FENETRE - DECLARATION. Dans ce paragraphe, on déclare les variables (listes, curseurs etc) accessibles seulement depuis les différents paragraphes de la fenêtre (Initialisation, Vérification, Validation, Evénements),
- FENETRE - EVENEMENTS. Dans ce paragraphe on écrira le code correspondant à chaque événement qui pourra être déclenché sur un objet,
- INITIALISATION. Dans ce paragraphe on écrira le code qui charge les données avant d'afficher la fenêtre,
- VERIFICATION. Dans ce paragraphe on écrira le code qui vérifie les données saisies dans la fenêtre par un utilisateur,
- VALIDATION . Dans ce paragraphe on écrira le code qui écrit les données dans la base après vérification.
- PROCEDURES . Des procedures peuvent être créées pour effectuer des actions répétivies ou bien pour rendre le code plus modulaire et lisible.
Un squelette typique de code pourrait être :
/* ___ Déclarations _____________________________________________________________________ DECL_PGM /* variables globales, DS, listes, curseurs, déclarations de paramètres du programme INIT_PGM INITIALIER WIN_2205 /* appeler le paragraphe de chargement des données EXECUTER WIN_2205 /* afficher la fenêtre à l'utilisateur WIN_2205 DECLARATION /* variables locales, DS, listes, curseurs INITIALISATION /* code à exécuter avant d'afficher la fenêtre OBJETS EVENEMENTS_OBJETS... BTN_VALIDATE BoutonGaucheClic VERIFIER /* appeler le paragraphe de vérification VALIDER /* appeler le paragraphe de validation TERMINER /* fermer la fenêtre en cours (aller à l'odre suivant l'ordre INITIALISER) VERIFICATION /* code qui vérifie les données saisies par l'utilisateur ENVOYER_MSG *EFFACER_TOUT /* effacer les messages d'erreur si [conditionErreur pour l'objet ZZ_JLP] preparer_msg hl21734 ZZ_JLP init_msg ZZ_JLP anomalie fin ... VALIDATION /* code pour mettre à jour la base de données après la vérification des données saisies par l'utilisateur MAJ_SQL ou CREER_SQL ou ...
Procédures
1 - Définition
Une procédure est un bloc de code appelable depuis un bloc du programme ou bien depuis l'exterieur du programme si la procédure est publique.
2 - Paramètres
3 - Appeler une procédure
Chaînes de caractère
1 - Concaténer des variables alphanumeriques
Pour concatener deux variables alphanumériques (ou plus) on utilisera les opérateurs // ou /// .
- // est un opérateur qui va concaténer le contenu exact des deux variables (la taille exacte de l'opérande de gauche sera concaténée à la taille exacte de l'opérande de droite)
- /// est un opérateur qui va éliminer les blancs qui sont en partie droite de l'opérande de gauche.
/* ___ Déclarations _____________________________________________________________________ ALPHA( 10) wLeft ALPHA( 10) wRight ALPHA( 20) wText1 ALPHA( 20) wText2 ALPHA( 20) wText3 /* ___ Code _____________________________________________________________________________ wLeft = 'Hello' wRight = 'World' wText1 = wLeft // wRight /* wText1 = 'Hello World ' wText2 = wLeft /// wRight /* wText2 = 'HelloWorld ' wText3 = wLeft /// ' ' // wRight /* wText3 = 'Hello World '
2 - Connaître la taille d'une chaîne de caractères
Pour connaître la taille d'une chaîne de caractères, il suffit d'utiliser la fonction prédéfinie &LONGUEUR_CHAINE
/* ___ Déclarations _____________________________________________________________________ num_bin_2 stringLength alpha(100) myString /* ___ Code _____________________________________________________________________________ myString = 'alpha beta' stringLength = &longueur_chaine(myString) /* stringLength a pour valeur 10
3 - Découper une chaine de caractères par rapport à un séparateur
Afin de découper une chaine de caractères en différentes chaînes (en une liste de chaines en réalité) par rapport à un séparateur, il suffit d'utiliser l'instruction SCINDER_CHAINE :
/* ___ Déclarations _____________________________________________________________________ alpha( 50) elementDay liste lst_days elementDay alpha(1000) myDays /* ___ Code _____________________________________________________________________________ myDays = 'Sunday;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday' scinder_chaine myDays ';' lst_days /* la liste "lst_days" contiendra 7 éléments : 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
4 - Remplacer une partie de chaine de caractères
Afin de remplacer une partie de chaine de caractères, il suffit d'utiliser l'instruction RECH_REMPLACER :
/* ___ Déclarations _____________________________________________________________________ alpha(1000) myDays alpha(1000) myDaysModified alpha( 56) mySearchString alpha( 78) myReplacementString /* ___ Code _____________________________________________________________________________ myDays = 'Sunday;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday' mySearchString = ';' myReplacementString = ' , ' myDaysModified = *blank rech_replacer myDays mySearchString myReplacementString myDaysModified /* la chaine myDaysModified contiendra 'Sunday , Monday , Tuesday , Wednesday , Thursday , Friday , Saturday'
5 - Ajouter un "retour chariot" dans une chaine de manière à avoir un retour à la ligne dans un champs d'un écran.
Afin d'ajouter un "retour" à une variable alphanumerique, il faudra créer une chaine alpha contenant le caractère "CR" (carriage return) et le caractère "LF" (line feed).
/* ___ Déclarations _____________________________________________________________________ ALPHA( 1) wCR ALPHA( 1) wLF ALPHA( 2) wCRLF ALPHA(100) wText /* ___ Code _____________________________________________________________________________ wCR = &CONVERSION_CAR('0D') wLF = &CONVERSION_CAR('0A') wCRLF = wCR // wLF wText = 'Hello' /// wCRLF /// 'world' z_display = wText
La propriété Multiligne de l'objet texte devra être cochée si vous voulez pouvoir voir le retour à l'écran.
Date, Time et Timestamp
1 - Effectuer des calculs sur des type date, time et timestamp
Afin d'effectuer des calculs sur des types Date, Time ou Timestamps, on utilisera les fonctions prédéfinies suivantes :
- &Calcul_Date
- &Calcul_Heure
- &Calcul_Timestp
/* ___ Déclarations _____________________________________________________________________ date myDate date myNewDate time MyTime time MyNewTime timestamp MyTimestamp timestamp MyNewTimestamp /* ___ Code _____________________________________________________________________________ myNewDate = &calcul_date(myDate;1;'Y') /* ajouter 1 année à myDate myNewDate = &calcul_date(myDate;-6;'M') /* soustraire 6 mois à myDate myNewDate = &calcul_date(myDate;40;'D') /* ajouter 40 jours à myDate myNewTime = &calcul_heure(myTime;1;'H') /* ajouter 1 heure à myTime myNewTime = &calcul_heure(myTime;-6;'M') /* soustraire 6 minutes à myTime myNewTime = &calcul_heure(myTime;40;'S') /* ajouter 40 secondes à myTime myNewTimestamp = &calcul_timestp(myTimestamp;1;'Y ') /* ajouter 1 année à myTimestamp myNewTimestamp = &calcul_timestp(myTimestamp;-6;'M ') /* soustraire 6 mois à myTimestamp myNewTimestamp = &calcul_timestp(myTimestamp;40;'D ') /* ajouter 40 jours à myTimestamp myNewTimestamp = &calcul_timestp(myTimestamp;1;'H ') /* ajouter 1 heure à myTimestamp myNewTimestamp = &calcul_timestp(myTimestamp;-6;'MI') /* soustraire 6 minutes à myTimestamp myNewTimestamp = &calcul_timestp(myTimestamp;40;'S ') /* ajouter 40 secondes à myTimestamp myNewTimestamp = &calcul_timestp(myTimestamp;-30;'MS') /* substraire 30 secondes à myTimestamp
2 - Calculer des intervales entre des types dates, time et timestamp
Afin de calculer des intervales entre des variables de type Date, Time and Timestamp, on utilisera les fonctions prédéfinies suivantes :
- &Ecart_Dates
- &Ecart_Heures
- &Ecart_Timestps
/* ___ Déclarations _____________________________________________________________________ date myDate1 date myDate2 time myTime1 time myTime2 timestamp myTimestamp1 timestamp myTimestamp2 num_e(9,0) myInterval1 num_e(9,0) myInterval2 num_e(15,0) myInterval3 /* ___ Code _____________________________________________________________________________ myInterval1 = &ecart_dates(myDate1;myDate2) /* nombre de jours entre myDate1 et myDate2 (la valeur peut être négative si myDate1 est plus grand que myDate2) myInterval2 = &ecart_heures(myTime1;myTime2) /* nombre de secondes entre myTime1 et myTime2 (la valeur peut être négative si myTime1 est plus grand que myTime2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'Y ') /* nombre d'années entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'M ') /* nombre de months entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'D ') /* nombre de jours entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'H ') /* nombre d'heures entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'MI') /* nombre de minutes entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'S ') /* nombre de secondes entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2) myInterval3 = &tms_interval(myTimestamp1;myTimestamp2;'MS') /* nombre de microsecondes entre myTimestamp1 et myTimestamp2 (la valeur peut être négative si myTimestamp1 est plus grand que myTimestamp2)
3 - Extraire des informations d'une variable de type Date
Afin d'extraire des informations d'une variable de type Date, on utilisera les fonctions prédéfinies suivantes :
- &Date_Annee
- &Date_Mois
- &Date_Jour
- &Date_Num
/* ___ Déclarations _____________________________________________________________________ date myDate num_e(4,0) myYear num_e(2,0) myMonth num_e(2,0) myDay num_e(8,0) myDateNum /* ___ Code _____________________________________________________________________________ myYear = &date_annee(myDate) /* extrait l'année de la date myDate (l'année sera au format SSAA) myMonth = &date_mois(myDate) /* extrait le mois de la date myDate myDay = &date_jour(myDate) /* extrait le jour de la date myDate myDateNum = &date_to_num(myDate) /* convertit la date myDate au format numérique (format SSAAMMJJ)
Image
1 - Transformer une variable alpha en variable image
Il est possible de transformer le contenu d'une variable de type alphanumérique en type image de la façon suivante :
/* ___ Déclarations _____________________________________________________________________ alpha( 100) fileAlias alpha( 10) fileMode alpha(5000) myAlpha image myImage num_bin_4 nb4ReturnCode /* ___ Code _____________________________________________________________________________ myAlpha = 'my text to be transformed to an image variable (2205) fileAlias = 'myTransformation' fileMode = 'w' charger_dll 'VATOOLBX.DLL' appeler_dll 'VATOOLBX.DLL' 'VaToolBxOpenFile' fileAlias myImage fileMode nb4ReturnCode appeler_dll 'VATOOLBX.DLL' 'VaToolBxWriteString' fileAlias myAlpha nb4ReturnCode appeler_dll 'VATOOLBX.DLL' 'VaToolBxCloseFile' fileAlias nb4ReturnCode decharger_dll 'VATOOLBX.DLL' /* la variable myImage contient le texte initialement contenu dans la variable myAlpha.
2 - Transformer une variable image en variable alpha
Si une variable de type Image contient seulement du texte, il est possible de transformer la variable de type Image en type alpha de la façon suivante :
/* ___ Déclarations _____________________________________________________________________ alpha( 100) fileAlias alpha( 10) fileMode num_bin_4 fileSize alpha(5000) myAlpha image myImage num_bin_4 nb4ReturnCode /* ___ Code _____________________________________________________________________________ fileAlias = 'myTransformation' fileMode = 't' fileSize = 5000 charger_dll 'VATOOLBX.DLL' appeler_dll 'VATOOLBX.DLL' 'VaToolBxOpenFile' fileAlias myImage fileMode nb4ReturnCode appeler_dll 'VATOOLBX.DLL' 'VaToolBxReadFile' fileAlias myAlpha fileSize nb4ReturnCode appeler_dll 'VATOOLBX.DLL' 'VaToolBxCloseFile' fileAlias nb4ReturnCode decharger_dll 'VATOOLBX.DLL' /* la variable myAlpha contient le texte alpha initialement contenu dans la variable myImage. /* la variable fileSize contient le nombre de caractères lu de la variable myImage.
Listes
1 - Déclarations
Une liste peut être declarée avec des variables , en référence à une entité logique , en reference à une autre liste , ou encore une combination de ces éléments .
/* ___ Déclarations de listes ___________________________________________________________ LISTE LST_EXAMPLE ELT_ONE ELT_TWO ELT_2205 /* définir une liste avec des éléments simples définis auparavant, ici les variables ELT_ONE, ELT_TWO et ELT_2205 LISTE LST_ART_ALC_2 *REF_MLD(HL_ART_ALCOOL) /* définir une liste avec toutes les propriétés de l'entité HL_ART_ALCOOL LISTE LST_ART_ALC_3 *REF_MLD(HL_ART_ALCOOL) *REF_MLD(HL_ART_LANGUE) /* définir une liste avec toutes les propriétés des entités HL_ART_ALCOOL et HL_ART_LANGUE LISTE LST_ART_ALC_4 *REF_MLD(HL_ART_ALCOOL) *REF_MLD(HL_ART_LANGUE) w_COD_ARTICLE_1 /* définir une liste avec toutes les propriétés des entités HL_ART_ALCOOL et HL_ART_LANGUE, plus la variable w_COD_ARTICLE_1 LISTE LST_ART_ALC_5 *REF_L(LST_ART_ALC_4) ELT_2205 /* définir une liste avec toutes les propiétés de la liste LST_ART_ALC_4, plus la variable ELT_2205
2 - Utilisation des listes
1 - Ajouter des éléments
Une liste est un objet mémoire structuré composé de colonnes, c'est similaire à une table, mais en mémoire.
Pour insérer des données dans une liste, il suffit de renseigner la valeur des variables colonnes de la liste, puis d'ajouter un élément à la list avec l'ordre L4G INSERER_ELT
Les éléments sont par défaut ajoutés à la fin de la liste (*FIN), mais on peut aussi les ajouter ...
- au début de la liste (INSERER_ELT *DEBUT)
- à la fin de la liste (INSERER_ELT *FIN)
- avant l'élément courant (INSERER_ELT *AVANT)
- après l'élément courant (INSERER_ELT *APRES)
- trié suivant une (ou plusieurs) colonne(s) (INSERER_ELT *TRI(...) )
Par default, les lignes insérées dans la liste ne sont pas considérées comme modifiées, mais on peut les indiquer comme modifées au moment de l'insertion si on veut retrouver plus tard ces éléments modifiés. Pour ce faire, il suffit d'ajouter *MODIF à l'ordre INSERER_ELT.
/* ___ Listes - exemples d'utilisation ___________________________________________ ELT_ONE = 1 ELT_TWO = 2 ELT_2205 = 2205 INSERER_ELT LST_EXAMPLE INSERER_ELT LST_EXAMPLE *DEBUT /* pour insérer un élément au début de la liste INSERER_ELT LST_EXAMPLE *FIN /* pour insérer un élément à la fin de la liste (comme c'est la valeur par défaut *FIN peut être omis) INSERER_ELT LST_EXAMPLE *AVANT /* pour insérer un élément dans la liste avant l'élément courant INSERER_ELT LST_EXAMPLE *APRES /* pour insérer un élément dans la liste après l'élément courant INSERER_ELT LST_EXAMPLE *TRI(ELT_2205 *DESC, ELT_TWO *ASC) /* pour insérer un élément dans la liste trié par ELT_2205 descendant, puis ELT_TWO ascendant (*ASC est la valeur défaut, peut être omis) INSERER_ELT LST_EXAMPLE *MODIF /* pour insérer un élément dans la liste ET en faire initialement un élément modifié (qui pourra être relu par LECTURE_LST LST_EXAMPLE *MODIF ...)
2 - Parcourir une liste
Afin de parcourir une liste, on pourra utiliser la boucle LECTURE_LST ... FIN_LECTURE_LST.
Dans la boucle de parcours d'une liste on est positionné sur un élément et on peut modifier (avec MODIFIER_ELT) ou supprimer (avec SUPPRIMER_ELT) l'élément courant.
/* ___ Liste - utilisations ______________________________________________________ LECTURE_LST LST_EXAMPLE /* ELT_ONE contient la valeur de la première ligne de la liste (pour la colonne ELT_ONE), de même pour ELT_TWO et ELT_2205 ... SI ... SUPPRIMER_ELT LST_EXAMPLE /* on peut supprimer l'élément courant FIB SI ... ELT_ONE = ELT_ONE + 1 MODIFIER_ELT LST_EXAMPLE /* on peut modifier les valeurs de l'élément courant en modifiant une (ou plusieurs) des colonnes qui le composent MODIFIER_ELT LST_EXAMPLE *SELECT /* en modifiant un élément on peut ajouter l'attribut SELECT ou DESELECT FIN FIN_LECTURE_LST /* ___ Pour une liste graphique, on peut parcourir les éléments sélectionnés par l'utilisateur ___ LECTURE_LST LST_GRAPHICAL *SELECT ... FIN_LECTURE_LST /* ___ Pour une liste graphique, on peut parcourir les éléments modifiés par l'utilisateur ou par programme si l'attribut *MODIF a été spécifié au moment de l'insertion ___ LECTURE_LST LST_GRAPHICAL *MODIF ... FIN_LECTURE_LST
On peut aussi utiliser une boucle manuelle avec LIRE_P_ELT (lire le premier élément) et LIRE_AV_ELT (lire l'élément suivant).
On peut également utililser LIRE_D_ELT (lire le denier élément) and LIRE_AR_ELT (lire l'élément précédent).
/* ___ Liste - utilisations ______________________________________________________ LIRE_P_ELT LST_EXAMPLE /* lecture du premier élément de la liste (s'il existe) TANT_QUE &CODE_LST(LST_EXAMPLE) = *NORMAL /* est-ce que l'opération a réussi ? ... LIRE_AV_ELT LST_EXAMPLE /* lecture de l'élément suivant (s'il existe) REFAIRE LIRE_D_ELT LST_EXAMPLE /* lecture du dernier élément de la liste (s'il existe) TANT_QUE &CODE_LST(LST_EXAMPLE) = *NORMAL /* est-ce que l'opération a réussi ? ... LIRE_AR_ELT LST_EXAMPLE /* lecture de l'élément précédent (s'il existe) REDO
3 - Parcourir une liste en utilisant des indexs
Afin de parcourir une liste pour chercher un élément (ou à partir d'un élément), on peut crééer et ustiliser des listes indexées (avec l'instruction INDEX_LIST).
On pourra alors utiliser les instructions LIRE_ELT (pour lire un élément) ou LIRE_P_ELT (pour accéder au premier élément supérieur ou égal à la valeur de l'index).
/* ___ Déclarations de listes ____________________________________________________ LISTE LST_EXAMPLE ELT_ONE ELT_TWO ELT_2205 /* définit une liste avec 3 "colonnes" précédemment déclarés, ici les variables ELT_ONE, ELT_TWO et ELT_2205 INDEX_LISTE MY_INDEX LST_EXAMPLE ELT_2205 /* définit l'index MY_INDEX qui va indexer la liste LST_EXAMPLE sur la colonne ELT_2205 /* ___ Liste - utilisations ______________________________________________________ ELT_2205 = 67 /* valeur qu'on veut atteindre dans la liste LIRE_ELT MY_INDEX /* on essaie de lire le premier élément de la list qui contiendrait la valeur 67 dans la colonne ELT_2205 SI &CODE_LST(MY_INDEX) = *NORMAL /* a-t-on trouvé ? ... /* si oui, alors on est positionné sur l'élément, on peut l'utiliser, le modifier ou le supprimer. FIN ELT_2205 = 67 LIRE_P_ELT MY_INDEX /* lire le premier élément dont la valeur de colonne LT_2205 est supérieure ou égale à la valeur positionnée pour l'index (67) TANT_QUE &CODE_LST(MY_INDEX) = *NORMAL /* est-ce que la dernière opération sur l'index a réussi ? ... LIRE_AV_ELT MY_INDEX REFAIRE DETRUIRE_INDEX MY_INDEX /* supprimer l'index si on ne l'utilise plus, pour libérer la mémoire qu'il utilise
Un index est créé au moment où on l'utilise pour la première fois en lecture.
Quand un index n'a plus d'utiliité dans le programme, on peut le détruire (pour libérer de la mémoire) avec l'instruction DETRUIRE_INDEX.
4 - Operations sur les listes
Pour vider une liste , on utilisera l'instruction L4G VIDER_LST,
Pour copier une liste dans une autre liste, on utilisera l'instruction L4G COPIER_LST,
Pour inserer une liste dans une autre liste, on utilisera l'instruction L4G INSERER_LST,
Pour trier une liste , on utilisera l'instruction L4G TRIER_LST.
/* ___ Utlisation de listes ______________________________________________________ VIDER_LST LST_EXAMPLE /* efface la liste, COPIER_LST LST_ONE LST_TWO /* copier le contenu de la liste LST_ONE dans la liste LST_TWO, /* les deux listes sont identiquesà la fin de l'opération, /* les deux listes doivent avoir la même structure, INSERER_LST LST_ONE LST_TWO /* ajoute le contenu de la première liste à la seconde liste, /* par défaut les éléments sont ajoutés à la fin de la liste de destination, mais on peut spécifier *DEBUUT, *FIN, *AVANT, *APRES INSERER_LST LST_ONE LST_TWO *DEBUT /* ajoute le contenu de la première liste au début de la seconde liste INSERER_LST LST_ONE LST_TWO *FIN /* ajoute le contenu de la première liste à la fin de la seconde liste INSERER_LST LST_ONE LST_TWO *AVANT /* ajoute le contenu de la première liste avant l'élément courant de la seconde liste INSERER_LST LST_ONE LST_TWO *APRES /* ajoute le contenu de la première liste après l'élément courant de la seconde liste TRIER_LST LST_EXAMPLE ELT_2205 *DESC, ELT_ONE /* trier la liste sur la colonne ELT_2205 en ordre décroissant et sur la colonne ELT_ONE par ordre croissant
SQL
1 - Valeurs nulles
Quand on lit des informations en provenance de la base de données, on doit parfois gérer des valeurs NULLES.
Par exemple si on veut gérer les valeurs MOYENNE (ou MIN, MAX etc) des colonnes, parfois le *COND(condition) ne retourne aucune ligne ou bien on peut avoir des valeurs nulles dans les colonnes spécifiées.
Et parfois il est important de savoir qu'il n'y a pas de valeur.
Pour faire celà, on utilisera des indicateurs.
/* ___ Declarations _____________________________________________________________________ num_bin_2 wIndAverage num_e( 8,2) wAverageValue num_bin_2 wIndMax num_e( 8,2) wMaxValue /* ___ Code _____________________________________________________________________________ lire_sql employee *col( moyenne(age) :wAverageValue :wIndAverage, - max(age) :wMaxValue :wIndMax - *cond( name='milkwater') /* recherche de la moyenne et du max des ages des employés dont le nom est égal à "milkwater" si wIndAverage = -1 /* pas de valeur pour la moyenne sinon /* ... fin si wIndMax = -1 /* pas de valeur pour le maximum sinon /* ... fin
2 - Enregistrements verrouillés
Une ou plusieurs lignes d'une table peuvent être verrouillées. Ceci peut être dû à un processus qui a modifié des éléments sans pour autant avoir validé (commit) les modifications. En conséquence, aucun autre processus ne pourra modifier les lignes avant qu'une instruction VALIDER_MAJ (ou ANNULER_MAJ) n'ait été exécutée.
Si un enregistrement verrouillé, alors il ne pourra pas être modifié. Par contre il pourra être lu par un autre utilisateur.
Le mot reservé *BLOQUE permet de vérifier si un enregistrement est verrouillé. On le consulte après un accès modifiant la base de données (MAJ_SQL ou SUPPRIMER_SQL etc..).
- *BLOQUE = '1' : l'enregistrement est verrouillé
- *BLOQUE = '0' : l'enregistrement n'est pas verrouillé (on peut également utiliser la constante _RECORD_LOCKED à la place de la valeur '1')
Attention
Par défaut Oracle attend un temps "infini" après une opération de mise à jour/suppression si un enregistrement est verrouillé.
La main sera rendue au programme seulement lorsque l'enregistrement aura été libéré.
Pour changer ce comportement, on utilisera la méthode 'VaToolBxSetTimeOut' de la VaToolBx library (cf exemple ci-dessous)
/* ___ Code _____________________________________________________________________________ /* ___ Forcer Oracle à répondre après un certain délai, même si l'enregistrment est verrouillé __________________________ /* ___ Dans l'exemple qui suit, une réponse sera fournie après 5 secondes au maximum. ___________________________________ /* ___ Le paramètre 'P' indique que toutes les requêtes soumises durant la session utiliseront ce délai _________________ /* ___ Le paramètre 'T' indiquerait que seule la requête suivante aurait ce délai _______________________________________ appeler_dll 'VATOOLBX.DLL' 'VaToolBxSetTimeOut' 5 'P' returnCodeBool /* ___ Tentative de mise à jour d'un enregistrement ___ maj_sql employee age = age + 1 - *cond( name = 'milkwater') if *bloque = '1' /* l'enregistrement est verrouillé else /* l'(les) enregistement(s) ne sont pas bloqués et ont été mis à jour end
Valeurs aléatoires
Pour générer des valeurs aléatoires, on peut utliiser les deux fonctions suivantes de la VaToolBx.
- VaToolBxSeedRand
- VaToolBxRandom
1 - VaToolBxSeedRand
La fonction VaToolBxSeedRand est utilisée pour réinitialiser le générateur de nombre pseudo-aléatoire, lequel est utilisé par la fonction VaToolBxRandom.
2 - VaToolBxRandom
La fonction VaToolBxRandom est utilisée pour generater une valeur aléatoire.
Le resultat est un nombre de type NUM_BIN_4 compris entre -2147483648 et 2147483647.
Pour avoir une valeur comprise entre 0 et X on peut utiliser les fonctions &VALEUR_ABSOLUE et &MODULO (voir l'example ci-dessous)
3 - Example
Example to retrieve a value between 1 and 10 :
/* ___ Declarations _____________________________________________________________________ num_e(6,0) wTime num_bin_4 wSeedValue num_bin_4 wRandomValue /* ___ Code _____________________________________________________________________________ /* ___ Generate a seed value ____________________________________________________________ time wTime wSeedValue = wTime call_dll 'vatoolbx.dll' 'VaToolBxSeedRand' wSeedValue /* ___ Generate a random value __________________________________________________________ call_dll 'vatoolbx.dll' 'VaToolBxRandom' wRandomValue /* ___ Calculate a value between 1 and 10 _______________________________________________ wRandomValue = &absolute_value(wRandomValue) wRandomValue = &modulo(wRandomValue;10) wRandomValue = wRandomValue + 1
Dynamic program call
We can use the CALL instruction to call a dynamic program, with static or even dynamic parameters
1 - Dynamic call examples
/* ___ Declarations _____________________________________________________________________ alpha( 10) wProgramObjectFileName alpha( 128) wProgramPublicProcedureName alpha(1000) wParameters num_e( 2,0) myParameterNum01 num_e( 2,0) myParameterNum02 /* ___ Code _____________________________________________________________________________ call myProgram call myProgram.myProcedure myParameterNum01= 22 call myProgram.myProcedure2 myParameterNum01 myParameterNum01= 22 myParameterNum02= 05 call myProgram.myProcedure2 myParameterNum01 myParameterNum02 /* ___ Dynamic program name and public procedure name ___________________________________ wProgramObjectFileName = 'mypgm' wProgramPublicProcedureName = 'myProcedure' call &wProgramObjectFileName.&wProgramPublicProcedureName wProgramObjectFileName = 'mypgm' wProgramPublicProcedureName = 'myProcedure2' myParameterNum01 = 22 call &wProgramObjectFileName.&wProgramPublicProcedureName myParameterNum /* ___ Dynamic program name, procedure name and parameters ______________________________ wProgramObjectFileName = 'mypgm' wProgramPublicProcedureName = 'myProcedure2' wParameters = '22 05' call &wProgramObjectFileName.&wProgramPublicProcedureName &wParameters
Users's attribute
User session can be used to store and retrieve values.
Warning
It is only available in client part of a cloud generated program (not in a server part or in a server program or in a windows program).
1 - Set an attribute value
To set a session private attribute value, we simply have to use the VaToolBxCloudSetUserAttribute fonction of the vaToolBx library :
/* ___ Declarations _____________________________________________________________________ alpha( 50) wAttributeName alpha(256) wAttributeValue /* ___ Code _____________________________________________________________________________ wAttributeName = 'myLabel' /* Label wAttributeValue = 'xxxyyyzzz' /* Value to be stored under the user session (must be alpha value) call_dll 'VaToolBx' 'VaToolBxCloudSetUserAttribute' wAttributeName - wAttributeValue
The scope of this setting is limited to the current session (logout / logon will destroy all values).
2 - Retrieve an attribute value
To retrieve a session private attribute value, we simply have to use the VaToolBxCloudGetUserAttribute fonction of the vaToolBx library :
/* ___ Declarations _____________________________________________________________________ alpha( 50) wAttributeName alpha(256) wAttributeValue num_bin_4 wAttributeLength /* ___ Code _____________________________________________________________________________ wAttributeName = 'myLabel' /* Label wAttributeValue = *blank wAttributeLength = 256 /* Size of the wAttributeValue variable call_dll 'VaToolBx' 'VaToolBxCloudGetUserAttribute' wAttributeName - wAttributeValue - wAttributeLength if *return_code = *normal /* wAttributeValue contains the value previously saved end
3 - Delete an attribute value
To delete a session private attribute value, we simply have to use the VaToolBxCloudSetUserAttribute fonction of the vaToolBx library with a blank value :
/* ___ Declarations _____________________________________________________________________ alpha( 50) wAttributeName alpha(256) wAttributeValue /* ___ Code _____________________________________________________________________________ wAttributeName = 'myLabel' /* Label wAttributeValue = *blank /* *blank to delete the label from the user's session call_dll 'VaToolBx' 'VaToolBxCloudSetUserAttribute' wAttributeName - wAttributeValue
Management Rules
Management rules (MR) can be used if we don't want to repeat the same code on different parts of the code.
The management rule can have parameters and must be seen as a text that will be parsed inside the code.
1 - Parameters
The parameter 1 of the MR will be placed in place of the :01 value etc.
The :01 (:xx) value can be present multiple times inside the MR.
The :01 (:xx) value can be placed anywhere in the code, even to replace an Adelia order or part of it.
/* ___ Management Rule "My_Beautiful_MR" ________________________________________________ /* ___ Declarations _____________________________________________________________________ decl alpha( 50) w:01_val decl ref(cli_usr_:02 client) wCli_usr_:02 decl num_e(9,0) sqlcode_mr /* ___ Code _____________________________________________________________________________ wcli_usr_:02 = :03 if wcli_usr_:02 = *blank wcli_usr_:02 = *user end upd_sql client cli_usr_:02 = :wcli_usr_:02 sqlcode_mr = *sqlcode :06 insert_mr BOL_TRC_:05('*DEBUG';'my beautiful MR, sqlCode : '//sqlcode_mr ;1) :04 = sqlcode_mr
2 - Usage
To use a MR, we simply have to insert it with the INSERT_MR order
/* ___ Code _____________________________________________________________________________ insert_mr my_beautiful_mr(test;cre;'milkwater';mrReturnCode;C; ) insert_mr my_beautiful_mr(test;maj;*blank;mrReturnCode;S;*)
Graphical objects
1 - get an object from his object name
In order to get the handle of an object from the name of the object it's possible to use the predefined function &GET_OBJECT :
/* ___ Declarations _____________________________________________________________________ graphic_object(colonne) colObjVar /* ___ Code _____________________________________________________________________________ colObjVar = &get_object('col_01') colObjVar:visibility = *true
Classes
Les classes sont utilisées notament pour consommer ou produire des services web
1 - JSON
Pour générer ou bien utiliser le format suivant dans un fichier JSON
{ ... "BarCodeList":[ "2205", "2206", "2207" ] ... }
Il faudra effectuer la déclaration suivante dans la définition de la classe Adelia MA_CLASSE :
*attributs { ... alpha( 32) BarCodeList() *ser_nom('BarCodeList'); ... }
Puis le code adelia suivant pour pouvoir générer des données dans ce élément :
alpha( 32) BarCodeList() *ser_nom('BarCodeList');
Resources
Ressources are typically used to import "external" objects in the adelia environment.
The advantage to import an object in the adelia environment is that we don't need any more the external object to use it.
It will be saved also with the backup of the environment.
1 - Creation of a resource
A resource is defined with
- name : public name of the object,
- Type : must be object,
- Program Type : where the program will be used (most of the time in windows and cloud clients)
- File name : name of the file if it is exported
- Destination : folder for the export of the resource (not used most of the time)
2 - Usage of a resource
In the BOL environment, the resources can be used for images.
When using an image (or icon) in a window, we should use a resource instead of importing the image from file system :
3 - Benefits of resources
When a resource is used (eventually in multiple programs), if we want to modify an object (image, icon, etc) , we just need to modify the resource, then analyze the resource in order to have the usage of the resource and generate the programs found.
For example, if we modify the "reduced icon" image, we just have to modify the resource used and generate the programs. We don't have to go to all the windows to change the Reduced Icon image again.
Logical Data Model
1 - How to retrieve the name of the Adelia Logical Entity from the name of the Table
In order to retrieve the name of the Adelia Logical Entity from the real name of the table , we can use the Maintenance manager accessible from the Session manager .
Then, if we select File/Table as object attribute , Logical Entity as Object type , BOLLOGP* (for example) as File name and if we press Find button , the system will show us with all the Adelia Logical files that have this part of name in the physical name :
2 - Property naming convention
The short name starts with the entity prefix (in this case RH) followed by 4 characters.
The associated fields starts with ZZ, followed by the same 4 characters.
The guide word is the same as the property name.
The associated guide word, starts with a Z followed by the name of the property without the entity prefix.
Code tips
/* ___ Declarations _____________________________________________________________________ num_e(3,0) wValue /* ___ Code _____________________________________________________________________________ if wValue = 1 or wValue = 5 or wValue = 8 then /* is equivalent to if wValue = 1;5;8 then if wValue <> 1 and wValue <> 5 and wValue <> 8 then /* is equivalent to if wValue <> 1;5;8 then
Search tips (using regular expression)
To search in the source code we can use L4G editor " File / Multisource search " function with the Regular expression check box selected.
1 - Search examples
/* ___ Search for the string XML_OPEN ... *CHECK __________ /* ___ . means any character __________ /* ___ * means any number of times __________ /* ___ .* means any character, any number of times __________ /* ___ \* means the special character * not interpreted as * (multiple) __________ XML_OPEN.*\*CHECK /* ___ Search for the string XML_OPEN ... 'XML' ... 'XML' __________ /* ___ . means any character __________ /* ___ * means any number of times __________ /* ___ .* means any character, any number of times __________ CONV_DATA.*'XML'.*'XML'
BOL debugging
1 - Trace a value
2 - Trace an image value
Added a new bol_trc_imagea management rule to log IMAGE variables.
This new management rule works like the BOL_TRC management rule, except it has a new parameter that will be concatenated to the text.
The image variable must contains text. It can be for example an image variable containing XML.
/* ___ Declarations _____________________________________________________________________ image wImage /* ___ Code _____________________________________________________________________________ insert_mr bol_trc_imagea('*DEBUG';'my text ';wImage;1)
BOL database scripts
1 - Set new PAPG values
PAPG example :
-- Create program configuration option MYCONFIG delete from wms.hlxprop where XPCPRG = 'MYCONFIG'; insert into wms.hlxprop values('MYCONFIG', 'My configuration', 'MYCONFIG', '007', '011', '0', '0', 0); delete from wms.hlpgpap where GKCPRG = 'MYCONFIG'; insert into wms.hlpgpap values('MYCONFIG',' ','1','0',' '); delete from wms.hlpapdp where GJCPRG = 'MYCONFIG'; insert into wms.hlpapdp values('MYCONFIG',1,'Code',3,' ',' ',' '); insert into wms.hlpapdp values('MYCONFIG',4,'Designation',100,' ',' ',' '); insert into wms.hlpapdp values('MYCONFIG',104,'Active',1,' ',' ',' ');
BOL REST services
1 - Call swagger REST API page
The url address of the swagger REST API page is :
2 - Generate the JWT token
To generate the JWT token, you'll have to access to the following url, but replace XXX with your reflex login and YYY with your reflex password
3 - Apply the JWT token
To apply the JWT token to the rest call, press the Authorize button on top of the REST API page.
Then enter "JWT" , a space character AND the token generated for your user/pass informations.
Then press Authorize button.
REFLEX REST services web
1 - Swagger et visualisation des web services spécifiques
Afin de pouvoir visualiser ses services web spécifiques dans l'interface de swagger, il faudra modifier le fichier de configuration wsRestConf.properties présent dans le répertoires de configuration reflex web (C:\Hardis\Reflex\conf en version windows)
On ajoutera la valeur ",com.hardis.reflex" à la ligne correspondant à la clef "SWAGGER2FEATURE.resourcePackage"
... SWAGGER2FEATURE.resourcePackage=com.hardis.reflex.publicapi,com.hardis.adelia.webservice,com.hardis.reflex ...
2 - Swagger et chapitres
Afin de regrouper les web services par types de services sans avoir à mettre tous les services (procédures) dans le même programme, il suffira d'ajouter dans le code de configuration "sw_configurer *service _ws_rest_swag_description ..." pour que le service soit ajouté à un groupe de web services.
Par exemple afin de regrouper des services web de test sous le chapitre "XXX - Web services de test (STUB)", il faudra écrire le code suivant dans le paragraphe DECL_PGM du programme contenant le(s) service(s) :
DECL_PGM ... sw_configurer *service _ws_rest_swag_description 'XXX - Web services de test (STUB)' ...
De cette façon, une fois le(s) service(s) généré(s), on verra le chapitre suivant dans swagger :