4D au pays des Widgets Résumé 4D Notes techniques

Transcription

4D au pays des Widgets Résumé 4D Notes techniques
4D au pays des Widgets
Par
Christophe KEROMEN, Cabinet de Consultants CKTI
Note technique 4D-200602-06-FR
Version 1
Date 1 février 2006
Résumé
Un widget est une mini-application autonome, dédiée à une tâche déterminée. Cette note technique montre
comment réaliser un widget affichant dans une palette flottante des informations récupérées depuis un
moteur 4D. Nous utilisons la technologie de Yahoo en raison de son fonctionnement multi plateforme, mais
la technique utilisée s’adapte sans difficulté à Dashboard, l’équivalent d’Apple apparu avec Tiger.
4D Notes techniques
Copyright © 1985-2006 4D SA - Tous droits réservés
Tous les efforts ont été faits pour que le contenu de cette note technique présente le maximum de fiabilité possible.
Néanmoins, les différents éléments composant cette note technique, et le cas échéant, le code, sont fournis sans garantie d'aucune sorte.
L'auteur et 4D S.A. déclinent donc toute responsabilité quant à l'utilisation qui pourrait être faite de ces éléments, tant à l'égard de leurs
utilisateurs que des tiers.
Les informations contenues dans ce document peuvent faire l'objet de modifications sans préavis et ne sauraient en aucune manière engager 4D
SA. La fourniture du logiciel décrit dans ce document est régie par un octroi de licence dont les termes sont précisés par ailleurs dans la licence
électronique figurant sur le support du Logiciel et de la Documentation afférente. Le logiciel et sa documentation ne peuvent être utilisés, copiés
ou reproduits sur quelque support que ce soit et de quelque manière que ce soit, que conformément aux termes de cette licence.
Aucune partie de ce document ne peut être reproduite ou recopiée de quelque manière que ce soit, électronique ou mécanique, y compris par
photocopie, enregistrement, archivage ou tout autre procédé de stockage, de traitement et de récupération d'informations, pour d'autres buts que
l'usage personnel de l'acheteur, et ce exclusivement aux conditions contractuelles, sans la permission explicite de 4D SA.
4D, 4D Calc, 4D Draw, 4D Write, 4D Insider, 4ème Dimension ®, 4D Server, 4D Compiler ainsi que les logos 4e Dimension, sont des marques
enregistrées de 4D SA.
Windows,Windows NT,Win 32s et Microsoft sont des marques enregistrées de Microsoft Corporation.
Apple, Macintosh, Power Macintosh, LaserWriter, ImageWriter, QuickTime sont des marques enregistrées ou des noms commerciaux de Apple
Computer,Inc.
Mac2Win Software Copyright © 1990-2002 est un produit de Altura Software,Inc.
4D Write contient des éléments de "MacLink Plus file translation", un produit de DataViz, Inc,55 Corporate drive,Trumbull,CT,USA.
XTND Copyright 1992-2002 © 4D SA. Tous droits réservés.
XTND Technology Copyright 1989-2002 © Claris Corporation.. Tous droits réservés ACROBAT © Copyright 1987-2002, Secret Commercial
Adobe Systems Inc.Tous droits réservés. ACROBAT est une marque enregistrée d'Adobe Systems Inc.
Tous les autres noms de produits ou appellations sont des marques déposées ou des noms commerciaux appartenant à leurs propriétaires
respectifs.
1 / 28
4D au pays des Widgets
Différentes notes techniques ont présenté des exemples d’applications tierces pouvant s’interfacer avec 4D.
Cette note technique montre comment réaliser un widget; Il s’agit d’une mini-application affichant dans une
palette flottante des informations récupérées depuis un moteur 4D.
Nous utilisons la technologie de Yahoo en raison de son fonctionnement multi plateforme, mais la technique
utilisée s’adapte sans difficulté à Dashboard, l’équivalent d’Apple apparu avec Tiger.
Présentation des widgets
L’idée de mini-applications autonomes, dédiées à une tâche déterminée, et fonctionnant dans leur propre
fenêtre n’est pas nouvelle, les plus anciens se souviendront des accessoires de bureau des anciens systèmes
Mac.
En février 2003, le concept est réapparu sur Mac OSX sous une forme graphiquement très élaborée avec les
widgets de Konfabulator. Demeurée relativement confidentielle, sans doute parce qu’il s’agissait d’un
produit payant et mono plate-forme, cette approche est aujourd’hui déclinée sous deux formes qui
rencontrent bien plus de succès :
• les yahoo !widgets, suite au rachat de Konfabulator par Yahoo et à sa mise à disposition gratuite ;
• les widgets de Tiger (technologie uniquement MacOSX).
Trois catégories
Les widgets se classent dans l’une des trois catégories suivantes :
• Les accessoires : ils sont autonomes et ne requièrent ni accès à Internet, ni à une autre application. On
y retrouvera les classiques horloges, calepins, calculettes, etc.
• Les applications : ce sont des modules couplées à une application existante comme iTunes ou Carnet
d’adresses. Ils procurent une interface simplifiée, souvent dédiée à la consultation d’une partie de
l’information. Leur fonctionnement est en général local à la machine.
• Les informateurs sont conçus pour échanger des données au travers d’un réseau, Internet ou Intranet.
Ils permettent de surveiller des processus ou d’avoir en permanence des informations disponibles dans
une palette flottante dans un coin de l’écran.
Points communs de ces différentes déclinaisons :
• réalisation graphique très poussée avec gestion de la transparence, donnant un aspect très ludique ;
• simplicité de l’interface ;
• personnalisation de l’aspect par l'utilisateur afin de faciliter l'appropriation.
Exemple de widget
Parmi les exemples classiques et qui se retrouvent aussi bien chez Yahoo qu’Apple, la prévision
météorologique. Vous pourrez ainsi constater qu’il fait beau au moins une fois par semaine en Bretagne.
2 / 28
Le widget Yahoo ! Weather
Malgré son apparente simplicité, ce widget est assez complexe, car outre un paramétrage assez important de
l’aspect visuel, il offre :
• par un clic sur la fenêtre la possibilité d’obtenir des informations plus détaillées affichées dans une
zone type ‘tooltip’ ;
• des possibilités d’interaction au travers par exemple des boutons ‘extented forecast’ et ‘info’ ;
• la possibilité de choisir la ville dont la prévision météo sera affichée et un menu déroulant (obtenu par
clic-droit ou ctrl-clic remémorant les dernières villes sélectionnées).
Quoique plus rarement, les widgets peuvent également proposer des zones de saisie, comme ici pour choisir
la ville concernée par l’affichage :
Exemple de dialogue saisissable dans un widget
Notons par la même occasion, qu’un widget n’est pas limité à une seule présentation, mais peut proposer
différentes interfaces suivant le contexte.
4D aussi !
4D Watcher
Au moment de la rédaction de cette note, 4D US a annoncé la disponibilité de son premier widget dédiée à la
surveillance d’informations du monde 4D, tout en promettant d’autres réalisations dans le futur. Félicitations
à 4D US, car le widget est fourni aussi bien en version Yahoo que Dashboard.
3 / 28
4D Watcher listant les échanges sur la liste iNug.
4D Quiz
Vous trouverez sur www.4dquiz.com un widget Dashboard permettant de rechercher dans la documentation
en ligne de 4D.
4D Quiz
Sécurité
Afin de prévenir les intrusions cachées sur le poste de l’utilisateur, le moteur de Yahoo demande
confirmation avant d’exécuter un nouveau widget.
4 / 28
Comparaison des deux technologies
Quoique d’un rendu très voisin et qui suscita les polémiques au moment de la sortie de Tiger, les deux
technologies diffèrent en réalité notablement dans leur réalisation.
Moteur d’exécution
Dashboard
Les widgets version Dashboard ne s’exécutent que sur Macintosh et seulement à partir de la version dite
Tiger d’OS X, soit la 10.4. Ils ne nécessitent alors aucun composant supplémentaire après téléchargement. La
technologie qui assure l’exécution des mini-applications se nomme Dashboard. Pour plus d’information,
consultez la liste des ressources à la fin de cette note technique.
Yahoo ! Widget Engine
Pour exécuter un widget modèle Yahoo, il faut télécharger et installer l’environnement d’exécution sur
chaque poste cible, l’équivalent du 4D Runtime. Cet inconvénient s’accompagne néanmoins d’une bonne
nouvelle : l’engine Yahoo est disponible pour OSX ET pour Windows :
http://widgets.yahoo.com/
Téléchargement de l’Engine.
Sur PC il faut disposer au minimum de Windows 2000 tandis que la compatibilité sur Macintosh démarre
avec Panther (version 10.3).
Notez que l’installation Windows pèse plus lourd que sa petite sœur MacOS car les développeurs ont dû
intégrer dans la version Windows des fonctions qui existent nativement dans l’OS d’Apple.
Autant de process que de Widgets
Inconvénient des widgets : c’est très joli…mais ça consomme beaucoup de mémoire ! Chaque miniapplication tourne en tant que telle dans son propre process et consomme aisément quelques méga-octets,
plus de la ressource processeur.
Affichage dans le gestionnaire des tâches de Windows
Encore une bonne chose dont il ne faut pas abuser !
Bien entendu, l’avantage recherché c’est l’étanchéité entre mini-applications. Chacune disposant de son
5 / 28
propre environnement d’exécution, aucun dysfonctionnement de l’une n’est susceptible de perturber le
fonctionnement des autres.
Programmation Yahoo ! widget
La programmation des widgets de Yahoo s’effectue par une combinaison :
• de déclaration XML des composants de l’application : objets d’interface et événements ;
• de code JavaScript pour le contrôle des opérations ;
• d’images, de préférence au format png (Portable Networks Graphics) pour l’aspect habillage.
Une extensibilité est possible au travers d’appels :
• à des applescripts sur OSX
• à des objets COM sur Windows.
En outre, il est possible d’effectuer des appels à des commandes Terminal. Cette fonction repose sur les
fonctionnalités natives UNIX de l’OS d’Apple et certaines commandes ont été émulées dans l’Engine
Windows pour assurer la portabilité.
La prise en main repose sur :
• un tutoriel disponible sur le site de Yahoo ;
• un guide de référence assez spartiate malgré ses 300 pages ;
• les milliers de widgets existants.
En effet, les composants internes d’un widget ne sont pas compilés et sont librement consultables.
Il n’existe pas d’IDE pour programmer les Widgets et il n’est pas toujours évident de mettre en pratique une
fonction décrite dans la documentation. Pour tester un widget il suffit à tout moment de cliquer sur son
fichier qui se lance alors dans l’environnement d’exécution.
Programmation Dashboard widget
Pour Tiger, un widget n’est rien d’autre qu’une page HTML utilisant les classiques : CSS2, DOM2,
JavaScript, HTML. On peut donc considérer qu’un widget Apple n’est qu’une page HTML présentée dans
Dashboard (qui utilise le moteur opensource WebCore comme Safari) et non dans un navigateur.
Les widgets Apple sont extensibles :
• au travers de programmation Cocoa ;
• par des appels à des lignes de commandes UNIX ;
• par recours à des plugs-ins Internet (Flash, Quicktime, Java, etc.)
Conséquences appréciables :
• Il est possible de tester directement (quoique partiellement) des widgets au sein de Safari et de
bénéficier des options de déboguage JavaScript ;
6 / 28
• Si vous connaissez HTML et les CSS, vous savez programmer un widget, au contraire des widgets
Yahoo qui demandent l’appropriation d’un langage déclaratif XML propriétaire.
Bien, je suppose que vous êtes maintenant impatients de voir d’un peu plus près la réalisation d’un exemple
communiquant avec une base 4D.
Exemple de réalisation avec 4D
Le principe retenu pour notre exemple de widget consiste à afficher une palette flottante qui envoie une
requête à 4D afin de récupérer de l’information présentée dans la palette.
Idées de réalisation
En réfléchissant à l’exemple à retenir, plusieurs idées nous sont venues.
Un exemple loisir avec Juke-Box
Parmi les widgets que j’utilise couramment, deux sont en relation avec iTunes. Je me suis donc fait la main
sur la réalisation d’un widget très simple qui affiche le titre du morceau en cours de lecture dans l’application
JukeBox de Roland Lannuzel et fournie gratuitement par 4D S.A.
Cet exemple, très basique, peut être affiné de différentes manières :
• en énonçant le morceau à chaque changement grâce à la fonction speak :
var textToSpeak = "Your computer is talking to you. What say you?";
7 / 28
speak(textToSpeak);
• en affichant d’autres informations sur le morceau ;
• en permettant de piloter le Juke-box depuis le widget.
Autres exemples possibles :
Impression d’enveloppes
Sur le modèle du Dashboard widget/ Enveloppes, le widget :
• récupère l’adresse de retour du courrier ;
• permet de placer un logo ;
• permet de saisir des premières lettres d’un contact et affiche les coordonnées du contact ;
• offre la possibilité de saisir l’adresse complètement ;
• imprime l’enveloppe.
Transfert de fichiers vers le serveur
Sur le modèle de FTPbeam, un glisser-déposer d’un document vers le widget équivaut à transférer le
document vers le serveur 4D qui se charge de le ranger et l’indexer.
Tableau de bord
Le widget présente des informations issues de 4D qui sert d’intégrateur en allant interroger différentes
sources de données : comptabilité, gestion, automates,…
Moniteur
Le widget liste, à des fins de surveillance, des processus en cours d’accomplissements sur le serveur 4D : par
exemple des imports réguliers ou des synchronisations entre sites distants.
Infos4D.widget
J’ai finalement retenu l’idée de présenter des informations sur l’application 4D en cours d’exécution et sur
son environnement. Au travers d’une simple palette flottante, toute information sur son environnement que
le langage 4D permet de récupérer devient ainsi consultable depuis n’importe quel ordinateur connecté à
Internet.
Pour son aspect multi plateforme, j’ai choisi une réalisation en widget Yahoo.
8 / 28
Le widget Infos4D
L’incontournable http
Pour communiquer, le widget et 4D doivent disposer d’un protocole commun : les widgets reposent sur http
pour communiquer avec l’extérieur. Nous trouvons ainsi une nouvelle illustration de l’ouverture
extraordinaire que représente la disponibilité d’un serveur http dans 4D lui-même. Malgré sa fréquente
restriction au simple usage de serveur Web, le serveur http de 4D constitue un outil de communication interapplications très puissant et reposant sur un standard !
Serveur http de 4D
4D reçoit une requête http (une seule dans cet exemple), traitée dans la méthode base ‘Sur connexion Web’.
J’ai généré une base exemple à partir du template 4D de gestion de contacts. Puis, j’ai simplement activé le
serveur Web de la base.
Voici le code de la Méthode base Sur connexion Web qui répond à la requête provenant du widget et lui
renvoie les informations souhaitées, structurées dans un flux XML :
C_TEXTE($1;$2;$3;$4;$5;$6)
Au cas ou
: ($1="/get_4Dinfos")
9 / 28
C_TEXTE($_vt_refRoot)
$_vt_refRoot:=DOM Creer ref XML("infos4D")
ADM_get_4D_infos ($_vt_refRoot)
C_BLOB($_vx_blobXML)
DOM EXPORTER VERS VARIABLE($_vt_refRoot;$_vx_blobXML)
ENVOYER BLOB HTML($_vx_blobXML;"text/xml")
DOM FERMER XML($_vt_refRoot)
Fin de cas
Ce code est totalement indépendant du client, il ne préjuge pas de son appel par le widget et se contente de
générer très simplement une structure XML bien formée.
Nous vérifions que ce code fonctionne correctement en saisissant comme URL dans notre navigateur local :
http://localhost/get_4Dinfos
Le navigateur nous affiche la réponse du serveur Web de la base :
la réponse XML du serveur 4D
Construction de la structure XML
La construction du contenu XML s’effectue dans la méthode ADM_get_4D_infos dont voici le source :
10 / 28
` ---------------------------------------------------` Nom utilisateur (OS) : christophe Keromen
` Date et heure : 28/02/06, 11:42:26
` ---------------------------------------------------` Methode : ADM_get_4D_infos
` Description :
` récupérer des infos sur 4D, l'appli en cours d'exécution et son environnement
`
` Parametres :
` $1:TEXTE:Ref Element racine
`
` Version : 1
` Appel : ADM_get_4D_infos (Ref Element racine )
` ---------------------------------------------------C_TEXTE($1;$_vt_refRoot)
$_vt_refRoot:=$1
C_BOOLEEN($_vb_siAutonome)
$_vb_siAutonome:=Vrai
C_BOOLEEN($_vb_siIndentation)
$_vb_siIndentation:=Vrai
DOM ECRIRE OPTIONS XML($_vt_refRoot;"UTF-8";$_vb_siAutonome;$_vb_siIndentation)
Si (Vrai) ` infos statiques
C_TEXTE($_vt_refStatiques)
$_vt_refStatiques:=DOM Creer element XML($_vt_refRoot;"infos_statiques")
C_TEXTE($_vt_versionApplication)
$_vt_versionApplication:=Version application(*) `Exemple : la chaîne "B0120602" représente
` une version beta 12 de la version 6.0.2
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refStatiques;"version_application";$_vt_versionApplication)
C_TEXTE($_vt_fichierApplication)
$_vt_fichierApplication:=Fichier application
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refStatiques;"fichier_application";$_vt_fichierApplication)
C_TEXTE($_vt_siCompile)
$_vt_siCompile:="oui"*Num(Application compilee)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refStatiques;"appli_compilee";$_vt_siCompile)
C_TEXTE($_vt_fichierStructure)
$_vt_fichierStructure:=Fichier structure
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refStatiques;"structure";$_vt_fichierStructure)
Fin de si
Si (Vrai) ` Fichier de données
C_TEXTE($_vt_refData)
$_vt_refData:=DOM Creer element XML($_vt_refRoot;"data")
C_TEXTE($_vt_fichierDonnees)
$_vt_fichierDonnees:=Fichier donnees
DOM_AJOUTER_ELEMENT_SIMPLE($_vt_refData;"fichiers";$_vt_fichierDonnees)
C_TEXTE($_vt_fichierDonneesVerrouille)
$_vt_fichierDonneesVerrouille:=("oui"*Num(Fichier donnees verrouille))
+("non"*Num(Non(Fichier donnees verrouille)))
DOM_AJOUTER_ELEMENT_SIMPLE($_vt_refData;"data_verrouillees";$_vt_fichierDonneesVerrouille)
11 / 28
TABLEAU ALPHA(255;$_taNomSegment;0)
LISTE SEGMENTS DE DONNEES($_taNomSegment)
C_TEXTE($_vt_nbreSegments)
$_vt_nbreSegments:=Chaine(Taille tableau($_taNomSegment))
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refData;"nbreSegments";$_vt_nbreSegments)
Fin de si
Si (Vrai) ` serialisation et licence
C_TEXTE($_vt_refSerial)
$_vt_refSerial:=DOM Creer element XML($_vt_refRoot;"infos_serialisation")
LIRE INFORMATIONS SERIALISATION($_vl_cle;$_vt_utilisateur;$_vt_société;$_vl_nbreConnexions;
$_vl_nbreConnexionsMax)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refSerial;"utilisateur";$_vt_utilisateur)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refSerial;"societe";$_vt_société)
DOM_AJOUTER_ELEMENT_SIMPLE($_vt_refSerial;"nbreConnexions";Chaine($_vl_nbreConnexions))
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refSerial;"nbreConnexionsMax";
Chaine($_vl_nbreConnexionsMax))
C_TEXTE($_vt_licenceDisponible)
Si (Licence disponible(Licence 4D Write ))
$_vt_licenceDisponible:="oui"
Sinon
$_vt_licenceDisponible:="Non"
Fin de si
$_vt_refElement:=DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refSerial;"licenceWrite";
$_vt_licenceDisponible)
Fin de si
Si (Vrai) ` informations dynamiques
C_REEL($_vn_totalMemory;$_vn_PhysicallMemory)
C_ENTIER LONG($_vl_FreeMemory;$_vl_process)
AP AVAILABLE MEMORY ($_vn_totalMemory;$_vn_PhysicallMemory;$_vl_FreeMemory;$_vl_process)
C_TEXTE($_vt_refStatiques)
$_vt_refStatiques:=DOM Creer element XML($_vt_refRoot;"infos_dynamiques")
DOM_AJOUTER_ELEMENT_SIMPLE($_vt_refStatiques;"totalMemory";
Chaine($_vn_totalMemory/(1024*1024);"### ### M"))
DOM_AJOUTER_ELEMENT_SIMPLE($_vt_refStatiques;"physicalMemory";
Chaine($_vn_PhysicallMemory/(1024*1024);"### ### M"))
DOM_AJOUTER_ELEMENT_SIMPLE($_vt_refStatiques;"freeMemory";
Chaine($_vl_FreeMemory/(1024*1024);"### ### M"))
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refStatiques;"processStack";
Chaine($_vl_process/1024;"### ### k")+(1000*"-"))
Fin de si
Note importante :
Attention, le moteur d’analyse XML (parseur) du widget n’aime pas les éléments vides. Plus exactement, il
faut vérifier qu’un élément porte une valeur textuelle avant d’essayer de la lire. Pour ne pas alourdir le code
JavaScript, nous n’avons pas effectué ces contrôles dans le widget de démo. C’est donc du côté 4D, qu’il
faut vérifier que chaque élément XML contient bien une valeur.
12 / 28
La méthode utilitaire DOM_AJOUTER_ELEMENT_SIMPLE qui permet d’ajouter directement un élément
simple et sa valeur au parent courant est la suivante :
` ---------------------------------------------------` Nom utilisateur (OS) : christophe Keromen
` Date et heure : 23/09/04, 07:04:31
` ---------------------------------------------------` Methode : DOM_AJOUTER_ELEMENT_SIMPLE
` Description :
` Ajout d'un element simple et de sa valeur
`
` Parametres :
` $1:TEXTE:Ref Element Parent
`$2:TEXTE:Nom Element
`$3:TEXTE:Valeur Element
`
` Version : 1
` Appel : DOM_AJOUTER_ELEMENT_SIMPLE(Ref Element Parent;Nom Element;Valeur Element )
` ---------------------------------------------------C_TEXTE($1)
C_TEXTE($_vt_RefParent)
$_vt_RefParent:=$1
C_TEXTE($2)
C_TEXTE($_vt_NomElement)
$_vt_NomElement:=$2
C_TEXTE($3)
C_TEXTE($_vt_ValeurElement)
$_vt_ValeurElement:=$3
C_TEXTE($_vt_RefElement)
`Ajout d'un champ et de sa valeur
$_vt_RefElement:=DOM Creer element XML($_vt_RefParent;$_vt_NomElement)
DOM ECRIRE VALEUR ELEMENT XML($_vt_RefElement;$_vt_ValeurElement)
Les commandes 4D appelées pour récupérer de l’information ne présentent pas de difficultés. Notez que
nous utilisons également 4D Pack pour obtenir des informations concernant la mémoire.
D’autres possibilités de récupération d’informations intéressantes existent mais n’ont pas été mises en œuvre
dans cet exemple. Nous les avons indiquées pour mémoire à la fin de la méthode encadrées par des Si(Faux) :
Si (Faux) `plug-ins
`Licence 4D Draw
`Licence 4D for OCI
`Licence 4D View
`Licence 4D Web
`Licence 4D Write
`Licence Web 4D Client
`Licence SOAP 4D Client
`Licence 4D SOAP
`Licence 4D ODBC Pro
Entier long
Entier long
Entier long
Entier long
Entier long
Entier long
Entier long
Entier long
Entier long
808464694
808465208
808465207
808464945
808464697
808465209
808465465
808465464
808464946
13 / 28
`Licence 4D for ADO
`Licence 4D for MySQL
`Licence 4D for PostgreSQL
`Licence 4D for Sybase
Entier long
Entier long
Entier long
808465714
808465712
808465713
TABLEAU ENTIER LONG($_Tl_tabNumeros;0)
TABLEAU TEXTE($_Tt_tabNoms;0)
LIRE LISTE PLUGIN($_Tl_tabNumeros;$_Tt_tabNoms)
Fin de si
Si (Faux) `environnement systeme
C_ENTIER LONG($vlPlatform;$vlSystem;$vlMachine;$vlLangue)
PROPRIETES PLATE FORME($vlPlatform;$vlSystem;$vlMachine;$vlLangue)
C_TEXTE($_vt_nomMachine;$_vt_nomPossesseur)
$_vt_nomMachine:=Nom de la machine
$_vt_nomPossesseur:=Nom du possesseur
Fin de si
Si (Faux) `informations sur les data
`Commandes et sections pour Définition structure
`Enregistrements dans table
`Lire parametre base ({table; }sélecteur)
`Taille cache données
`Timeout 4D Server
Entier long
13
`Timeout 4D Client
`Mode écriture cache
`Numéro automatique table
Fin de si
Réalisation du widget
Intéressons-nous maintenant à la réalisation de la partie cliente, le widget. Outre l’aspect interface que nous
verrons plus loin, comment s’effectue la communication http avec 4D ?
Communication
URL.fetch()
Depuis l’origine, les widgets disposent d’une fonction JavaScript URL.fetch() qui permet de récupérer de
l’information depuis un serveur http. La méthode utilisée est GET ou POST et si le serveur renvoie du XML,
celui-ci doit être analysé "manuellement".
XMLHTTPRequest
Depuis la version 3 de l’Engine, un nouvel objet de communication est proposé : XMLHTTPRequest.
Derrière ce nom un peu barbare se cache le fondement d’une des évolutions les plus notables du Web actuel.
Initialement proposé par Microsoft pour Internet Explorer, cet objet est maintenant également supporté par
Safari et Firefox. Il permet au code JavaScript d’une page HTML d’échanger de l’information avec le
serveur Web SANS provoquer le rafraîchissement complet de la page. Couplé avec le Dynamic HTML
(modification du contenu de la page au moyen de l’objet DOM piloté par JavaScript), il s’agit du fameux
14 / 28
Ajax dont la presse informatique fait grand cas et qui représente l’un des piliers de la fameuse évolution vers
le Web version 2. Cette approche fait l'objet d'une note technique dédiée.
Avantages de cet objet :
• son API est commune avec celles des autres implémentations (celles des navigateurs) ;
• il charge directement les informations retenues dans un arbre DOM qu’il suffit d’interroger pour
récupérer les données à afficher.
Le code JavaScript de communication
Voici un exemple de fonction JavaScript se chargeant de la communication avec 4D :
function get4Dinfos()
{
var req = new XMLHttpRequest();
req.open( "POST", "http://192.168.1.13/get_4Dinfos", false );
req.send();
if ( req.status == 200 )
{
try
{
var docXML=req.responseXML;
//print( docXML.toXML() );
doParse(docXML);
}
catch(e)
{
print("An error occurred: " + e);
}
}
else{
razControls();
}
}
Commentaires
var req = new XMLHttpRequest();
C’est la ligne qui créé en mémoire un nouvel objet XMLHttpRequest, référencé dans la variable req.
req.open()
La méthode open de l’objet XMLHttpRequest est invoquée pour ouvrir une communication avec l’url
souhaitée en utilisant la méthode POST en mode synchrone (le code attend la réponse avant de
poursuivre).
req.send()
La requête HTTP vers l’url est réellement envoyée et la réponse est reçue et analysée
req.status
Cette propriété de l’objet reçoit le code statut de la requête http, 200 indique que tout s’est bien déroulé
15 / 28
req.responseXML
Cette propriété de l’objet contient l’arbre DOM correspondant à l’analyse du contenu XML de la
réponse.
Note :
La ligne passée en commentaire :
print( docXML.toXML() );
permet lorsque le commentaire est retiré d’envoyer vers la console de débogage le contenu de l’arbre DOM.
Nous y reviendrons plus loin.
Note :
Sur MacOSX, pour que ce code fonctionne il faut que la requête POST envoie réellement des données. Nous
modifierons donc le code en conséquence afin d’envoyer une structure XML minimale, ne contenant qu’un
élément racine <root>. Se reporter plus loin au listing de get4Dinfos pour cela.
Structure du widget
Un widget est déclaré par une structure XML comprenant des éléments dotés de propriétés.
Voici la structure principale de l’exemple :
16 / 28
La racine est l’élément widget, son attribut minimumVersion précise qu’il faut disposer au minimum de la
version 3.0 de l’Engine pour utiliser le widget, car c’est la version où a été introduite l’objet
XMLHTTPRequest.
L’objet about-box permet de définir une ou plusieurs images qui serviront à l’affichage d’un à propos.
L’objet window contient par défaut les autres composants d'interface. En dehors d’un certain nombre de souséléments (title, height, width, visible, opacity, level, shadow) qui permettent de préciser certaines propriétés,
on peut constater que window comprend plusieurs autres éléments correspondant à des déclarations d’objets
d’interface :
• deux images : l’une servant pour le fond, l’autre pour afficher un bouton ("Refresh" afin de renvoyer
une requête vers 4D pour rafraîchir les informations) ;
• quatre éléments text qui afficheront de l’information relue depuis l’arbre DOM ;
• un élément textarea sur lequel nous reviendrons dans un second temps.
Au même niveau que l’élément window (en "sibling" pour reprendre la terminologie adéquate), nous
trouvons :
17 / 28
• deux éléments preference qui indiquent les préférences par défaut que le widget offre en modification ;
• deux éléments action qui décrivent les actions à effectuer lorsque l’événement indiqué comme valeur
de l’attribut "trigger" est déclenché. Nous déclarons ainsi deux gestionnaires d’événements, l’un sur
chargement du widget (onLoad), l’autre sur modification des préférences par l’utilisateur
(onPreferencesChanged).
Les champs Text
Les quatre premières lignes d’information sont affichées par des champs texte. Voici un exemple de
déclaration :
<text>
<name>version_4D</name>
<color>#FEFEFE</color>
<size>13</size>
<alignment>left</alignment>
<vOffset>60</vOffset>
<hOffset>30</hOffset>
</text>
Le sous-élément name identifie de manière unique un objet dans la structure et servira d’identifiant pour
manipuler l’objet par code JavaScript.
Les autres sous-éléments décrivent des propriétés de l’objet : couleur, taille, alignement, position horizontale
et verticale.
Il est également possible de déclarer un objet Text directement par programmation :
newObjectName = new Text()
Déclaration du bouton
Voici la déclaration du bouton :
<image src="Resources/btn_GO.png">
<name>buttonGo</name>
<vOffset>450</vOffset>
<hOffset>430</hOffset>
<onMouseUp>
get4Dinfos();
</onMouseUp>
</image>
On y retrouve des propriétés identiques à celles du Text (name, vOffset, hOffset, …).
L’apparence du bouton est décrite par une image dont le chemin d’accès est précisé dans l’attribut « src ».
L’action effectuée par le bouton est définie en déclarant un gestionnaire d’événement get4Dinfos(), fonction
JavaScript qui sera appelée sur l’événement onMouseUp, c'est-à-dire sur clic souris.
Les balises d’actions
La description du comportement du widget s’effectue au travers de balises <action>. Voici le code de
l’élément action correspond à l’événement onLoad, c'est-à-dire sur chargement du widget :
<action trigger="onLoad">
include("infos4D.js");
version_4D.data ="chargement..."
get4Dinfos()
18 / 28
updateBehavior();
</action>
Tout d’abord, la commande include permet d’inclure un fichier externe. Dans notre exemple, ce fichier
"infos4D.js" contiendra toutes les fonctions JavaScript nécessaires au fonctionnement du widget.
Ensuite nous affectons la chaîne "chargement… " à la propriété data de l’objet Text version_4D.
Puis nous appelons successivement les fonctions JavaScript contenues dans le fichier externe : get4Dinfos()
et updateBehavior();.
Les fonctions JavaScript
Par le mécanisme associant déclaration de gestionnaire d’événements et possibilité de définir le code
JavaScript dans un ou plusieurs fichiers externes, nous obtenons une séparation des couches satisfaisantes.
Voici le code de la fonction updateBehavior() qui applique des propriétés de mise en forme sur chargement et
aussi après modification des préférences par l’utilisateur :
function updateBehavior()
{
version_4D.font = preferences.textFontPref.value;
version_4D.color = preferences.textColorPref.value;
fichier_appli.font = preferences.textFontPref.value;
fichier_appli.color = preferences.textColorPref.value;
appli_compil.font = preferences.textFontPref.value;
appli_compil.color = preferences.textColorPref.value;
structure.font = preferences.textFontPref.value;
structure.color = preferences.textColorPref.value;
myTextArea.font= preferences.textFontPref.value;
myTextArea.color = preferences.textColorPref.value;
}
L’objet preferences est automatiquement géré par le widget Engine.
Enfin le code de la fonction get4Dinfos() qui gère la communication entre le widget et 4D :
function get4Dinfos()
//pour le Mac
var docXML;
docXML=XMLDOM.createDocument();
root=docXML.createElement("root");
docXML.appendChild(root);
//pour le Mac (fin)
var req = new XMLHttpRequest();
print (req);
req.open( "POST", "http://192.168.1.162/get_4Dinfos", false );
req.send(docXML);
if ( req.status == 200 )
{
try
{
var docXML=req.responseXML;
19 / 28
//print( docXML.toXML() );
doParse(docXML);
}
catch(e)
{
print("An error occurred: " + e);
}
}
else{
print('req.status : '+req.status);
razControls();
}
Dans un premier bloc, nous retrouvons l’objet XMLHTTPRequest présenté plus haut :
var req = new XMLHttpRequest();
req.open( "POST", "http://localhost/get_4Dinfos", false );
req.send(docXML);
Puis en cas de succès (req.status == 200), nous chargeons le résultat dans un arbre DOM
var docXML=req.responseXML; : nous appelons alors une fonction JavaScript qui analyse la structure XML et
affecte les valeurs aux objets d’interface : doParse(docXML);.
La méthode d’analyse du XML : doParse
Voici pour la première partie de cette fonction :
// les champs TEXT
version_4D.data="version 4D : "+docXML.evaluate( "string(infos4D/infos_statiques/version_application)") ;
fichier_appli.data="appli : "+docXML.evaluate( "string(infos4D/infos_statiques/fichier_application)") ;
appli_compil.data="application compilée : "+docXML.evaluate( "string(infos4D/infos_statiques/appli_compilee)") ;
structure.data="structure : "+docXML.evaluate( "string(infos4D/infos_statiques/structure)") ;
La propriété data des objets Text est renseignée d’après la valeur relue dans un élément par le code :
docXML.evaluate("string(infos4D/infos_statiques/version_application)").
La fonction docXML.evaluate() évalue une expression XPath (la désignation d’un élément XML dans la
hiérarchie par une expression de chemin) pour retrouver un élément précis et la fonction string() convertit la
valeur de cet élément en chaîne.
Les balises de préférences
Nous retrouvons le même mécanisme déclaratif pour décrire les deux préférences que le widget offre en
modification à l’utilisateur : la couleur du texte et la police d’affichage :
<preference>
<name>textColorPref</name>
<title>Text Color:</title>
<type>color</type>
<defaultValue>#FEFEFE</defaultValue>
<description>Sélectionner la couleur du texte.</description>
</preference>
20 / 28
Voici le dialogue de préférences correspondant :
Dialogue de préférences
Insistons sur le fait que ce dialogue s’obtient simplement en deux déclarations ! Seules deux préférences sont
proposées par défaut :
• le niveau de la fenêtre, c'est-à-dire le comportement de la fenêtre par rapport aux autres fenêtres :
Flottante, Avant-plan, Normale, Arrière-plan, Affichage à tête-haute uniquement (expression étrange
désignant un mode n’affichant que les widgets) ;
• l’opacité de la fenêtre (qui permet de fixer sous forme de pourcentage la transparence).
Préférences par défaut
Plus de généricité avec une TextArea
Lourdeur de l’approche déclarative
Définir, comme nous l’avons fait jusque-là, chaque information par la déclaration d’un objet Text est long et
peu générique. Une première amélioration passerait par une déclaration par programmation d’un objet Text
associé à un élément de la structure XML.
Une autre possibilité consiste à concaténer les informations relues depuis la structure XML dans un autre
type d’objet, la TextArea, qui permet le multilignes.
21 / 28
Déclaration du nouvel objet
On utilise l’élément <textarea> :
<textarea>
<name>myTextArea</name>
<color>#FEFEFE</color>
<size>13</size>
<alignment>left</alignment>
<vOffset>120</vOffset>
<hOffset>30</hOffset>
<width>350</width>
<height>350</height>
<editable>false</editable>
</textarea>
Notez l’élément <editable> qui permet de déclarer comme saisissable ou non le contenu de la zone.
Remplissage par programmation
Nous avons, côté 4D, regroupé les informations par thème :
Si (Vrai) ` Fichier de données
C_TEXTE($_vt_refData)
$_vt_refData:=DOM Creer element XML($_vt_refRoot;"data")
C_TEXTE($_vt_fichierDonnees)
$_vt_fichierDonnees:=Fichier donnees
$_vt_refElement:=DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refData;"fichiers";$_vt_fichierDonnees)
C_TEXTE($_vt_fichierDonneesVerrouille)
$_vt_fichierDonneesVerrouille:=("oui"*Num(Fichier donnees verrouille))
+("non"*Num(Non(Fichier donnees verrouille)))
$_vt_refElement:=DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refData;"data_verrouillees";
$_vt_fichierDonneesVerrouille)
TABLEAU ALPHA(255;$_taNomSegment;0)
LISTE SEGMENTS DE DONNEES($_taNomSegment)
C_TEXTE($_vt_nbreSegments)
$_vt_nbreSegments:=Chaine(Taille tableau($_taNomSegment))
$_vt_refElement:=DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_refData;"nbreSegments";
$_vt_nbreSegments)
Fin de si
Voici la structure XML correspondante :
<data>
<fichiers>
D:\Server_DEV\4D_NT_CK\_en cours\contacts\contacts.4DD
</fichiers>
<data_verrouillees>non</data_verrouillees>
<nbreSegments>1</nbreSegments>
</data>
22 / 28
Nous dédions une portion de code JavaScript à l’exploitation d’une telle structure. Il ne suffit plus de
récupérer la valeur d’un élément XML désigné par un chemin XPath comme précédemment, nous devons
recourir à une navigation DOM depuis l’élément parent <data> :
// DATA
myTextArea.data="\nData\n";
var myitem=docXML.evaluate("infos4D/data");
var firstItem=myitem.item(0);
for(var i = 0; i < firstItem.childNodes.length; i++)
{
var zeChild=firstItem.childNodes.item(i).firstChild;
myTextArea.data+="* "+firstItem.childNodes.item(i).tagName+" : "+zeChild.data+"\n";
}
: référence le premier enfant de infos4D/data, la numérotation commence à 0
La collection des enfants est contenue dans firstItem.childNodes et le nombre d’élements s’obtient par la
propriété length de cette collection. Nous bouclons sur chacun des éléments pour en extraire :
var firstItem=myitem.item(0);
• le nom de l’élément : firstItem.childNodes.item(i).tagName
• la valeur de l’élément : firstItem.childNodes.item(i).firstChild.data
La notion importante est que dans DOM la valeur d’un élément est un noeud de type texte porté par le
premier enfant de l’élément lui-même. A l’instar d’autres bibliothèques de code (en Java par exemple), cette
subtilité est masquée dans 4D qui ne considère que l’élément et masque la notion de nœud.
Nous trouverons dans le code JavaScript, autant de portions de code équivalentes que de regroupement
d’informations. Bien entendu, il serait souhaitable de retravailler ce code pour en faire une fonction
paramétrable.
Le résultat final
23 / 28
Le widget sous Windows avec une barre de défilement.
Notez pour l’objet TextArea :
• la barre de défilement verticale, gérée automatiquement ;
• le retour à la ligne automatique dans la zone.
C’est pour mettre en évidence ces automatismes que nous avons artificiellement rajouté des tirets après la
dernière information.
Finalisation
La majeure partie du travail est effectuée. Reste à aborder deux aspects :
• le mode déboguage ;
• le "paquetage", c'est-à-dire l’étape finale pour bâtir un widget exploitable par l’utilisateur final.
Désactivation du mode debug
Juste sous la déclaration du widget, se trouve l’élément debug qui indique si, lors de l’exécution, la console
doit s’afficher ou non :
<debug>on</debug>
24 / 28
Console de Yahoo ! Widget Engine
Les valeurs possibles pour l’élément sont : errors, on, off, verbose. Se reporter au manuel de référence pour
leur signification.
Sans recourir à cet élément, le raccourci-clavier "control et touche majuscule" lors de la sélection du menu
du Widget Engine permet de faire apparaître une option "Debug mode" dans le menu. Le fait de cocher cette
option provoquera l’affichage de la console pour tous les widgets lancés par la suite.
Les actions proposées sous forme de boutons se résument à pouvoir recharger le widget et le fermer.
La zone supérieure de la fenêtre permet d’afficher des informations par programmation pour suivre
l’exécution du programme, par exemple :
print( docXML.toXML() );
affiche le contenu du flux XML contenu dans docXML. La commande log() peut également être utilisée. Les
erreurs rencontrées sont automatiquement reportées dans cette zone ainsi que les chargements, comme ici
celui du fichier JavaScript "infos4D.js".
Possibilités de déboguage
Il est aussi possible de provoquer des actions par saisie de commandes dans la zone "Evaluate". Voici ce
qu’indique l’aide en ligne :
Widget Engine Debugging Commands:
/dump object
print all the properties of 'object'
/trace function
print a message every time 'function' is called
/untrace function
stop tracing 'function'
/watch object.property
display a message when the given 'property' of 'object' changes
(arbitrary JavaScript)
execute the given JavaScript
/help
this list of commands
En saisissant par exemple /trace doParse, puis en cliquant sur le bouton "Refresh" du widget, on obtient
l’affichage suivant :
Tracepoint set
03/11/06 09:40:03.625: Traced function called: doParse()
25 / 28
La commande /dump est intéressante car elle permet d’obtenir toutes les propriétés d’un objet ainsi que les
valeurs courantes de ces propriétés. Par exemple pour /dump myTextArea :
Object "myTextArea":
myTextArea[color]: #FEFEFE
myTextArea[colour]: #FEFEFE
myTextArea[scrollbar]: true
myTextArea[data]:
Data
* fichiers : D:\Server_DEV\4D_NT_CK\_en cours\contacts\contacts.4DD
(…)
myTextArea[font]: Arial
myTextArea[name]: myTextArea
myTextArea[hOffset]: 30
myTextArea[vOffset]: 120
myTextArea[height]: 350
myTextArea[width]: 350
myTextArea[zOrder]: 7
myTextArea[opacity]: 255
myTextArea[alignment]: left
myTextArea[onMouseDown]: null
myTextArea[onMouseUp]: null
myTextArea[onMouseEnter]: null
myTextArea[onMouseExit]: null
myTextArea[onKeyDown]: null
myTextArea[onKeyUp]: null
myTextArea[onKeyPress]: null
myTextArea[onDragEnter]: null
myTextArea[onDragExit]: null
myTextArea[onMouseMove]: null
myTextArea[onDragDrop]: null
myTextArea[text]:
(…)
myTextArea[tooltip]:
myTextArea[size]: 13
myTextArea[style]: none
myTextArea[bgOpacity]: 0
myTextArea[bgColor]: #FFFFFF
myTextArea[bgColour]: #FFFFFF
myTextArea[lines]: true
myTextArea[columns]: true
myTextArea[editable]: false
myTextArea[spellcheck]: true
myTextArea[hAlign]: left
myTextArea[vAlign]: top
myTextArea[contextMenuItems]:
myTextArea[window]: [object Window]
myTextArea[onMultiClick]: null
myTextArea[onContextMenu]: null
myTextArea[secure]: false
myTextArea[visible]: 1
myTextArea[superview]: [object Root]
myTextArea[onLoseFocus]: null
myTextArea[onGainFocus]: null
myTextArea[thumbColor]: null
Vous pouvez ainsi constater que nous n’avons fait qu’effleurer le sujet des propriétés des objets !
Cependant, il n’existe pas de mode trace comme on peut en trouver dans 4D.
26 / 28
« Packaging »
La structure du Widget doit être la suivante : un dossier "Contents" comprenant les différents éléments du
widget. Ce dossier widget étant lui-même contenu dans un dossier portant le nom du widget suivi de
l’extension . widget.
Organisation du widget
L'étape finale de réalisation du paquetage diffère suivant la plateforme. Sur Macintosh, l’opération est
terminée ! Le widget se présente comme un paquet affichant l’icône caractéristique des widgets. Pour
obtenir maintenant son contenu, il faudra sélectionner l’option ‘Afficher le contenu du paquet’ dans le menu
contextuel obtenu par ctrl-clic sur l’élément dans le Finder.
Sur Windows en revanche, il faut recourir au glisser-déposer sur un widget fourni en libre téléchargement sur
le site de Yahoo : Widget_Converter. Le widget ainsi obtenu est une archive au format zip. Remplacez
l’extension .widget par .zip et vous pourrez consulter le contenu de tout widget.
Ressources
Voici une liste de ressources complémentaires pour votre voyage au pays des widgets. Bonne route…
Yahoo ! widgets
• Le site officiel : http://widgets.yahoo.com/
• Le forum konfabulator : http://www2.konfabulator.com, compte plus de 13 000 membres.
• Un wiki très intéressant et non dépendant de Yahoo est à consulter
konfabulator.wikicities.com/wiki/Unofficial_Konfabulator_Wiki
• Article dans le n° 81 de « Programmez ! »
Dashboard pour Tiger
• http://www.apple.com/fr/macosx/features/dashboard/
• Un très bon article sur les différences de fond entre entre Dashboard et Konfabulator :
http://daringfireball.net/2004/06/dashboard_vs_konfabulator
• Developing Dashboard Widgets: Quick and easy mini-applications. :
http://developer.apple.com/macosx/dashboard.html
• Tutorial « Build a Dashboard Widget” :
http://www.macdevcenter.com/pub/a/mac/2005/05/06/dashboard.html
• Traduction en français :
27 / 28
ici :
•
•
•
•
http://www.projectomega.org/article.php?lg=fr&php=tuts_dashboard&p=1
Dashboard Programming Guide :
http://developer.apple.com/documentation/AppleApplications/Conceptual/Dashboard_Tutorial/index.ht
ml
Dashboard Reference :
http://developer.apple.com/documentation/AppleApplications/Reference/Dashboard_Ref/
Des exemples de widgets sur la page Dashboard Sample Code :
http://developer.apple.com/samplecode/AppleApplications/idxDashboard-date.html
Dossier dans le n° 13 de « Vous et votre Mac »
Les ressources complémentaires conseillées par O’Reilly :
• JavaScript: The Definitive Guide, 4th Edition by David Flanagan (O'Reilly Media, 2001)
• Cascading Style Sheets: The Definitive Guide, 2nd Edition by Eric Meyer (O'Reilly Media, 2004)
• Dynamic HTML: The Definitive Reference, 2nd Edition by Danny Goodman (O'Reilly Media, 2002)
28 / 28