SlideShare une entreprise Scribd logo
Google Web Toolkit 1.5 JW-GWT
Ce qui précède n'affecte en rien vos droits en tant qu'utilisateur  (exceptions au droit d'auteur : copies réservées à l'usage privé du copiste, courtes citations, parodie...)  Ceci est le Résumé Explicatif du  Code Juridique (la version intégrale du contrat) .
Plan du séminaire
Google Web Toolkit – Plan Général (1) Introduction Les technologies du Web 2.0 Les principes d’Ajax Les applications RIA L’approche de GWT Développer une appli GWT Installation Créer et tester une application Les fenêtres et les panels Les composants graphiques Gestion de l’internationalisation Les feuilles de styles CSS Le modèle événementiel
Google Web Toolkit – Plan Général (2) Communications asynchrones Présentation de GWT RPC Impact des comm. asynchrones Implémenter un service Sérialisation Gestion des exceptions Utilisation de JSON Gestion de l'historique Notions avancées Utilisation d’images Intégration Java EE Tester avec Junit Présentation de JSNI
Introduction
Naissance des RIA (1) L'histoire du développement d'applications a connu plusieurs grandes phases Les terminaux passifs (années 70) La révolution du client-serveur (années 80) La révolution internet et intranet (années 90) L'évolution vers les 'clients riches' (années 2000) RIA = Rich Internet Application. RDA = Rich Desktop Application GWT
Naissance des RIA (2) Les terminaux passifs Terminaux connectés à un mainframe (3270), interface en mode texte, tout est géré par le serveur La révolution du client-serveur L'équipement des utilisateurs en postes de travail (PC) a permis le développement de la bureautique dans un premier temps puis celui du client-serveur Client serveur 1ère génération  : toute la logique sur le client, communication avec un serveur de données (bases de données, mainframes…), souvent nommé  'Client lourd' Client serveur 2ème génération  : gestion de l'interface graphique sur le poste client et interaction avec une partie applicative exécutée côté serveur (CORBA, DCOM, …)
Naissance des RIA (3) La révolution internet et intranet A partir de 1995, internet se développe et les utilisateurs se familiarisent avec l'utilisation d'un navigateur En parallèle, les équipes de développement sont confrontées aux limites du client-serveur (essentiellement le problème de déploiement et de gestion des mises à jour) L'infrastructure technique d'internet (HTTP, HTML, navigateur) va progressivement se généraliser en entreprise. Les applications intranet sont, au début, surtout réservées pour de la consultation. Au fil des ans, elles vont devenir de plus en plus sophistiquées Pour les utilisateurs et les exploitants l'architecture Web est un progrès majeur. Pour les développeurs, le passage est plus délicat : le couple HTTP/HTML n'a pas été conçu pour faire des applications. Principales technologies pour le développement d'applications Intranet : Java EE, PHP, .NET
Naissance des RIA (4) L'évolution vers les 'clients riches' Les demandes d'applications intranet de plus en plus sophistiquées se sont heurtées aux limites graphiques du HTML Manque d'interactivité, composants graphiques basiques, nécessité de faire des allers-retours pour une simple information à rafraîchir… Plusieurs solutions ont émergé, regroupées sous le terme 'clients riches'. Leur but : combiner la richesse ergonomique du client-serveur avec la souplesse de l'architecture Web RIA (Rich Internet Application)  : le navigateur web reste le socle côté client. Les possibilités du navigateur sont soit exploitées au maximum (Javascript et CSS) soit enrichies par l'ajout de plugins (Flash, Silverlight, JavaFX, …) RDA (Rich Desktop Application)  : renaissance du client-serveur 2ème génération, prévoit des solutions pour le problème d'installation et de mise à jour (ex: Eclipse RCP)
RIA, Web 2.0 et Ajax Le terme Web 2.0 résume l'évolution vers plus de richesse des sites internet Désigne surtout des aspects non techniques (les sites deviennent plus collaboratifs, participatifs, …) Techniquement utilisation importante de JavaScript JavaScript Créé en 1995 par Netscape. Permet d'intégrer, dans les pages HTML, des scripts interprétés par le navigateur D'abord utilisé pour limiter les échanges avec le serveur en assurant des contrôles de saisie côté client Progressivement deux utilisations majeures se sont démocratisées :  Ajax  et  DHTML
Ajax En 2005, le terme Ajax est apparu mettant un nom sur une pratique de plus en plus courante Ajax = Asynchronous JavaScript and XML Du code JavaScript émet des requêtes HTTP pour échanger des flux XML avec la partie serveur (objet XMLHttpRequest) Ce code peut s'exécuter indépendamment des actions de l'utilisateur Permet, par exemple, le rafraîchissement d'une partie de la page ou encore le remplissage progressif d'un arbre ou d'une table Rend les applications plus interactives en évitant les rafraîchissements complets des pages Réduit les flux échangés avec le serveur en se limitant aux données nécessaires
DHTML Après avoir téléchargé un fichier HTML, le navigateur créé en mémoire un arbre représentant la structure de la page puis l'affiche Le DOM : Document Objet Model Le contenu du DOM peut être manipulé dynamiquement en utilisant JavaScript Ajout et suppression de nœuds Modification d'attributs (emplacement, style, …) La mise au point du JavaScript est délicate Différences de fonctionnement entre les navigateurs. Environnements de développement sommaires Des frameworks JavaScript ont émergés : jQuery, prototypeJS, Scriptaculous…
L’approche de GWT Mai 2006 : annonce de GWT à la conférence JavaOne Google Web Toolkit Ecrire ses applications clientes en Java Les compiler en Javascript Javascript = le bytecode du web Compris par tous les navigateurs Bas niveau, puissant
Avantages de l'approche GWT Développer et maintenir des applis Javascript Supportant les spécificités des navigateurs Gère automatiquement Internet Explorer, FireFox, Mozilla, Safari, Opéra Gère automatiquement les différences entre les versions des navigateurs Supportant l'internationalisation Supportant des alternatives de configuration (intranet/extranet) De plus en plus complexes Java est conçu pour gérer des développements complexes Optimales Produit des versions spécifiques plutôt que génériques des fichiers Utiliser la myriade d'outils du monde Java IDE, conception, analyse de code, test, intégration continue, … Ne pas redévelopper tout ça une nouvelle fois
Principes généraux (1) Mise à disposition de librairies de classe Java Classes graphiques (widgets, panels) Permettent de composer une application type "client desktop" comme du Swing Classes de communication avec le serveur Permettent d'échanger des informations structurées (XML, JSON, …) Permettent même d'échanger directement des objets Java Permettent d'intégrer coté client des services écrits dans différents langages Compilateur de Java vers Javascript Supporte une version simplifiée du JRE Possibilité d'intégrer des frameworks Javascript Scriptaculous, JSCalendar, TinyMCE, MooTools, Ext-JS… Intégration possible avec les frameworks j2ee JSF, Spring, Struts, EJB, …
Principes généraux (2) Développement des applications reste difficile Tests unitaires avec JUnit Navigateur interne pour la mise au point (mode "hosted") Pas de déploiement préalable Le code qui s'exécute est du code Java Debug en Java, points d'arrêt, … Compiler en JavaScript ensuite Déployer et tester (mode "web")
Schéma général Compilateur Java->Javascript JRE Emulation JSNI JavaScript Native Interface Widgets &Panels I18n RPC Gestion de l'historique (bouton "Back") XML Parser Intégration JUnit
Compilation Java Transformation du code source Java Décrivant des classes, des méthodes Respectant la syntaxe Vers du bytecode Code binaire 'interprétable' par une machine virtuelle (JVM) Des instructions machines mais pour une machine virtuelle JVM = fonctions de base (natives) + gestion mémoire Résolution des références avec le ClassPath Contient notamment le JRE (les classes de base du système) En particulier le noyau (java.lang)
Compilation GWT Java vers JavaScript Exécuter la classe com.google.gwt.dev.GWTCompiler Avec une définition de "module" et un fichier de configuration Module = ensemble de fichiers liés (Java et autres) Configuration indique typiquement un point d'entrée : la classe principale Le compilateur part de ce point d'entrée Et suit les dépendances Ne compile que ce qui est utilisé Minimiser la taille des fichiers générés Utiliser des grosses bibliothèques sans risquer de surcharger le runtime final Produit des fichiers JavaScript Spécifiques pour chaque navigateur et pour chaque locale Attention : n'utilise que les fichiers Java (pas les .class) Nécessité de disposer des sources de toutes ses librairies utilisées
Modes de compilation Mode "OBFUSCATE" Nom de classes, d'attributs, de méthodes, … sont compressés Illisible mais compact (protège aussi son code) Mode "PRETTY" Noms courts On reconnaît au moins le nom des méthodes Mode "DETAILED" Noms complets Permet de refaire le lien avec le code Java en cas de bug
Fichiers générés ("permutation") Autant de fichiers que de combinaisons Type de navigateur Locale Propriété de configuration (typiquement internet/intranet) Les fichiers ne sont pas génériques Ne contiennent pas des "if" pour gérer les spécificités Un fichier de sortie = une "permutation" Le navigateur ne reçoit pas de code inutile Diminue l'utilisation de la bande passante Diminue l'empreinte mémoire dans le navigateur
Intégration JSNI Méthodes natives En Java : méthodes dont le code existera dans la jvm JavaScript Native Interface Spécifier des méthodes "natives", dont le code existera au runtime Intégrer le code JavaScript directement dans le code Java On met le code en commentaire derrière la définition Ça reste du code Java valide puisque dans des commentaires Le compilateur insère ce code dans le fichier généré Permet D'optimiser De gérer des spécifités, d'intégrer des librairies existantes public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
JRE Emulation Reprend un sous ensemble des classes de base Java Fournit un équivalent JavaScript de ces classes Packages java.lang, java.util, java.lang.annotation Assez complet mais pas toutes les méthodes Package java.io OutputStream, PrintStream, Serializable Package java.sql Date, Time, Timestamp
Limitations Syntaxe Java 5 (enum, types génériques, …) Supportée depuis GWT 1.5 La librairie du JRE est volontairement limitée Certaines subtilités Float/Double ne peuvent pas servir de clé dans une HashMap String.replaceAll, replaceFirst, split : regexp de JavaScript StringBuffer(int) et StringBuffer se comportent pareils System.out et err existent mais ne servent pas en mode web Pas de support des stack-trace dans les Throwable Vector : pas de capacité, de grossissement, de vérification d'indices Laisse entrevoir les types de problèmes à prévoir Mais pas si gênant que ça, il suffit de créer/utiliser d'autres librairies
Comparaisons Swing Logique similaire mais pas de MVC (pas de modèle), pas de Layout Echo2 Logique similaire mais tourne côté serveur Beaucoup plus d'appels vers le serveur et nécessité d'un serveur J2EE JSF Compliqué, tourne côté serveur, pas vraiment du client riche On peut intégrer du GWT dans des applis JSF et autres "struts like" Ruby on Rail Plutôt côté serveur avec automatismes ajax générés sur le client Pas aussi interactif (GWT est plus orienté client)
Développer une appli GWT
Installation Vérifier la présence d'un JRE Version 1.5 supportée depuis GWT 1.5 Téléchargement sur le site officiel http://code.google.com/intl/fr/webtoolkit/download.html Fichier compressé (gwt-windows-1.5.3.zip pour Windows) Décompresser : c'est prêt On utilisera aussi un IDE Outillage offre des facilités pour eclipse Mais tout autre IDE convient aussi
Installation : arborescence obtenue C:\GWT │  about.html  │  about.txt │  applicationCreator.cmd  script de création d'application │  benchmarkViewer.cmd │  COPYING │  COPYING.html │  gwt-benchmark-viewer.jar │  gwt-dev-windows.jar │  gwt-ll.dll │  gwt-module.dtd │  gwt-servlet.jar │  gwt-user.jar │  i18nCreator.cmd  script d'internationalisation │  index.html  point d'entrée html (doc et exemples) │  junitCreator.cmd  script de création tests junit │  projectCreator.cmd  script de création de projet (eclipse) │  release_notes.html │  swt-win32-3235.dll │ ├─── doc  répertoire de documentation ... └─── samples  répertoires d'exemples
Créer et tester une application Script "applicationCreator" Fait partie des fichiers installés Pour créer une application simple (type "Hello World") Permet de créer l'arborescence et les fichiers de base Package doit se terminer par le sous package ".client" Propose des options (qu'on verra plus tard) applicationCreator -out dir className
Créer et tester une application : création Création d'une application simple App Fichiers produits applicationCreator -out TP1 com.oxiane.formation.tp1.client.App C:\GWT\TP1 │  App-compile.cmd  script compilation JavaScript │  App-shell.cmd  script exécution mode hosted │ └─── src  répertoire source └─── com └─── oxiane └─── formation └─── tp1  package de l'application │  App.gwt.xml  description du module GWT │ ├─── client  package client (code du client) │  App.java  classe "point d'entrée" │ └─── public  package public (fichiers web) App.css  Feuille de style css de l'appli App.html  Fichier html de chargement web
Tester l'application : mode "hosted" Utiliser le script "App-shell" généré Ouvre un "GWT Development Shell" Sert de console (trace) Ouvre un "Hosted Browser" Internet Explorer sous Windows Mozilla sur les autres OS Exécution en Java Exceptions capturées Debug Java possible Moteur tomcat embarqué Moteur de servlet Déploiement automatique du code serveur
Fichiers ajoutés par le mode "Hosted" Mode "Hosted" ajoute une arborescence tomcat Tomcat embarqué dans le GWT Shell Development C:\GWT\TP1 …  code de l'application inchangé └─── tomcat  arborescence simplifiée tomcat ├─── conf │  │  web.xml │  │ │  └─── gwt  │  └─── localhost ├─── webapps │  └─── ROOT │  └─── WEB-INF │  web.xml  conf de l'application web │ └─── work  répertoire de travail tomcat └─── gwt └─── localhost └─── _ tldCache.ser  cache des taglib descriptors
Tester l'application : mode "Web" Utiliser le script "App-compile" généré Ou utiliser le bouton Compile/Browse du "Hosted Browser"
Fichiers ajoutés par le mode "Web" Mode "Web" utilise la version compilée JavaScript C:\GWT\TP1 ...  répertoires inchangés └─── www  répertoire ajouté ├─── .gwt-tmp  tmp de compilation │  └─── compiler │  └─── com.oxiane.formation.tp1.App  … └─── com.oxiane.formation.tp1.App  répertoire de l'appli … │  App.css │  App.html … │  com.oxiane.formation.tp1.App.nocache.js  appli JavaScript … └─── gwt  fichiers gwt TP 1
Utilisation dans un IDE Développement GWT = Développement Java pur N'importe quel IDE convient si on respecte l'arborescence Outillage spécifique pour eclipse Scripts proposent l'option "-eclipse" Gère les fichiers spécifiques tels que ".project" et ".classpath" ".launch" pour lancer les scripts avec les menus "Run as" Projet directement importable dans eclipse Ou IDE capable d'importer des projets eclipse (Netbeans,…) Utiliser le script "projectCreator" en premier Création de la structure de projet Ne pas oublier l'option "-eclipse nomProjet" avec les autres scripts
Cycle de développement Scripts = cycle de dév Ne pas oublier "-eclipse" Internationalisation Préparation du projet Fichier de propriétés JUnit Préparation du projet Classe de test prête à remplir projectCreator Eclipse ? applicationCreator I18n ? i18nCreator JUnit ? junitCreator Import du projet Fin Début Eclipse ? O N O O O N N N
Script "projectCreator" Création de la structure de projet Remarques Utiliser au moins "-ant" ou "-eclipse" (les deux sont possibles) projectCreator [-ant nomProjet]  Générer un script Ant de compilation des sources (extension ".ant.xml" ajoutée) [-eclipse nomProjet]  Création pour un projet eclipse [-out répertoire]  Répertoire de génération ("." par défaut) [-overwrite]  Ecraser les fichiers existants (alerte sinon) [-ignore]  Ignorer les fichiers existants (ne pas écraser) [-addToClassPath entrée]  Ajouter une entrée au classPath
Script "applicationCreator" Création de l'application par défaut Remarques Classe doit être dans un sous-package "client" (alerte sinon) En mode eclipse Génération de ".launch" pour lancer les scripts Mise à jour des fichiers spécifiques eclipse (.classpath, .project, …) applicationCreator [-eclipse nomProjet]  Création pour un projet eclipse [-out dir]  Répertoire de génération ("." par défaut) [-overwrite]  Ecraser les fichiers existants (alerte sinon) [-ignore]  Ignorer les fichiers existants (ne pas écraser) [-addToClassPath entrée]  Ajouter une entrée au classPath [-addModule module]  Ajouter un module GWT dans l'héritage nomCompletClasse  Nom complet de la classe à créer
Script "i18nCreator" Création du support de l'internationalisation On étudiera cela en détail plus tard Le principe général est d'utiliser une interface dans le code Propose une méthode pour chaque "constante" à internationaliser Implémentation automatique à partir de fichiers de propriétés i18nCreator [-eclipse nomProjet]  Création pour un projet eclipse [-out répertoire]  Répertoire de génération ("." par défaut) [-createConstantsWithLookup]  ConstantsWithLookup plutôt que Constants [-createMessages]  Messages plutôt que Constants [-overwrite]  Ecraser les fichiers existants (alerte sinon) [-ignore]  Ignorer les fichiers existants (ne pas écraser) nomCompletInterface  Nom complet de l'interface à créer
Script "junitCreator" Création du support de JUnit On étudiera cela en détail plus tard Le principe général est de préparer le projet à l'utilisation de JUnit Création des répertoires Création d'une classe pour écrire ses tests En mode eclipse, création d'un ".launch" pour lancer l'exécution des tests junitCreator -junit cheminJUnit  Chemin vers le jar de junit -module nomModule  Nom du module GWT à utiliser [-eclipse nomProjet]  Création pour un projet eclipse [-out répertoire]  Répertoire de génération ("." par défaut) [-overwrite]  Ecraser les fichiers existants (alerte sinon) [-ignore]  Ignorer les fichiers existants (ne pas écraser) [-addToClassPath entrée]  Ajouter une entrée au classPath
Import dans eclipse Import de projet existant Recopier les fichiers dans le workspace Ou bien générer directement dans le répertoire du workspace
Autres alternatives de création de projet Ecrire les fichiers à la main Pas très réaliste Disposer d'un assistant de création dans l'IDE Plugin eclipse GWT, support natif de GWT dans IntelliJ, … Existent mais n'apportent pas énormément GWT évolue encore, mieux vaut utiliser les outils fournis Recopier/générer l'arborescence de fichiers Permettrait de préparer un squelette institutionnel d'application Dans tous les cas, même structure finale TP 2
Cypal Studio (1) Plugin eclipse pour simplifier l'utilisation de GWT Site http://code.google.com/p/cypal-studio/ Assistants Création de modules : remplace projectCreator et applicationCreator Création de services (concerne la communication serveur) Lanceur en mode Hosted Problèmes Projet peu actif Ne couvre pas les possibilités des outils GWT tels que junitCreator Intéressant mais pas fondamental
Cypal Studio (2) Installation Pré-requis :  Eclipse IDE for Java EE Developers  (Eclipse + WTP) Dézipper dans le répertoire 'dropins' d'Eclipse et relancer Eclipse Configuration Indiquer l'emplacement de GWT dans les préférences
Cypal Studio (3) Création d'un projet Cypal fonctionne pour les projets de type 'Dynamic Web Project' Module Version 2.4  obligatoire (version de la spec servlet) Choisir la configuration 'Cypal Studio for GWT'
Cypal Studio (4) Création d'un module GWT A partir de menu 'File->New…' lancer l'assistant de création de module GWT
Cypal Studio (5) Pour tester Ouvrir le gestionnaire des configurations de lancement Créer une configuration de  lancement 'GWT Hosted Mode Application' Sélectionner le projet associé et le module GWT à lancer
Les composants graphiques
Interface EntryPoint L'interface désignant un point d'entrée d'application Méthode onModuleLoad() Equivalent au main() de l'application ou au service() des Servlets Coder une classe implémentant cette interface La désigner dans le fichier de description de module <entry-point class='com.oxiane.formation.tp1.client.App'/> Le compilateur part de cette classe  Et suit les dépendances public class App implements EntryPoint { public void onModuleLoad() { Label label = new Label(&quot;Hello world !&quot;); RootPanel.get().add(label); } }
Les fenêtres et les panels Notions classiques des interfaces graphiques Widget = contrôle utilisé par l'utilisateur Exemple : boutons, champs de saisie, etc. Panel = conteneur de widgets (ou d'autres panels) Exemple : table disposant un bouton et un champ en ligne En réalité, un panel peut aussi offrir de l'interactivité Window = la fenêtre du navigateur Accès aux méthodes, propriétés et événements du navigateur Dans la pratique, trois types de composants Widget Panel pour disposer (layout) Panel pour interagir Panel Widget Widget Panel Widget
Window Classe encapsulant la fenêtre du navigateur Équivalent de l'objet &quot;window&quot; de JavaScript Méthodes statiques, permettent d'interroger/piloter le navigateur Méthodes et propriétés (getter et/ou setter) diverses Accès aux dimensions utiles, au titre, à la zone de status, au scroll Dialogues simples : alert, confirm, prompt Pilotage : print, open (ouverture d'un autre navigateur) Gère des listeners (WindowClose et WindowResize) Contient une autre classe Window.Location Pour tout ce qui est spécifique à l'url
RootPanel Panel racine Associé à un élément de la page Créé par le framework Obtenu par la méthode statique get(String) Paramètre identifie un élément html Permet d'ajouter des widgets sur n'importe quel élément html identifié Panel racine par défaut Méthode get() sans paramètre Utilisé généralement dans le EntryPoint Dans le onLoadModule(), pour ajouter les widgets
Les composants graphiques Widget : classe Java En général en correspondance avec un équivalent HTML Button, TextBox, TextArea, CheckBox, RadioButton, … Différentes variations de la table HTMLTable, Grid, FlexTable Des composants plus spécifiques TabPanel : widgets dans différents onglets PopUpPanel StackPanel Plus de 30 widgets et panels en tout Présentés dans le Showcase (exemples de l'aide) TP 3
UIObject La racine des objets graphiques Encapsule un élément DOM Propriété &quot;element&quot; Gère un style associé à cet élément Méthodes getStyleName, addStyleName, … (on verra plus tard les styles CSS) Gère un positionnement et des dimensions Propriétés &quot;width, &quot;height&quot;, &quot;size&quot;, &quot;pixelSize&quot;, &quot;absoluteLeft&quot;, &quot;absoluteTop&quot;, … Gère un &quot;title&quot; Attention : texte de bulle d'aide et non un titre Gère la visibilité de l'élément Gère un masque d'événements Méthodes sinkEvents() et unsinkEvents() (on verra plus tard les événements)
Début de hiérarchie (UIObject) UIObject MenuItem MenuItemSeparator TreeItem Widget Composite FileUpload FocusWidget Frame Hidden Hyperlink Image Label MenuBar Panel Tree NamedFrame
Widget Classe abstraite héritant de UIObject Possède une représentation DOM interne Correspond à la &quot;vision&quot; JavaScript Méthodes positionnant des propriétés Positionne en réalité des attributs de style Exemple : setHeight(&quot;100px&quot;); setPixelSize(100,200); Propriété &quot;title&quot; correspond à la bulle d'aide Préférer l'utilisation des feuilles styles Permet de bien séparer le fonctionnel de la présentation Propose aussi d'autres méthodes Accès au panel conteneur et gestion des événements (plus tard) UIObject Widget
MenuBar, MenuItem et Command MenuBar Contient des MenuItem et MenuItemSeparator Horizontal par défaut (booléen pour basculer) MenuItem Libellé + Command ou MenuBar (menus hiérarchiques) Construction simplifiée avec addItem() MenuItemSeparator addSeparator() Command Interface pour représenter une action Méthode execute() invoquée lorsqu'on cliquera sur l'item Généralement implémentée avec une classe interne anonyme UIObject Widget MenuBar
Interfaces HasText et HasHTML HasText Identifie un composant contenant un texte Propose les méthodes setText() et getText() Propose en général un constructeur avec String Exemples : MenuItem, Button, Label, Hyperlink, … HasHTML Identifie un composant contenant du texte HTML Hérite de HasText Propose les méthodes setHTML() et getHTML() Propose en général un constructeur avec un String et un booléen &quot;asHTML&quot; Booléen indique si le texte doit être interprété comme texte HTML ou non Exemples : MenuItem, TreeItem, Button, …
Interface HasAnimation Marque un widget utilisant une animation Propose de quoi tester et activer l'animation Méthode isAnimationEnabled() Méthode setAnimationEnabled(boolean) Exemple MenuBar, DialogBox, TabPanel, …
MenuBar : exemple MenuBar menu = new MenuBar(); MenuBar menuFichier = new MenuBar(true); menuFichier.addSeparator(); Command cmdPlusTard = new Command() { public void execute() { Window.alert(&quot;pas implémentée !&quot;); } }; menuFichier.addItem(&quot;Quitter&quot;, cmdPlusTard); menu.addItem(&quot;Fichier&quot;, menuFichier); MenuBar menuAide = new MenuBar(true); menuAide.addItem(&quot;A propos&quot;, new Command() { public void execute() { ouvrirAPropos(); } }); menu.addItem(&quot;Aide&quot;, menuAide); RootPanel.get().add(menu); TP 4
Widget : Image Un widget pour afficher une image Préciser une URL Soit dans le constructeur Soit dynamiquement avec le setter Répertoire &quot;public&quot; de l'application Pour les ressources statiques Notion de &quot;ViewPort&quot; Permet de n'afficher qu'une partie de l'image Préciser le rectangle visible dans le constructeur ou avec le setter Peut réagir à des événements (on verra plus tard) UIObject Widget Image
Widget : Frame Un widget pour encapsuler un site Utilise un frame invisible (IFRAME) Préciser l'url (on peut la changer dynamiquement) La sous-classe NamedFrame Ajoute une propriété &quot;nom&quot; Permettra de l'utiliser comme cible d'un FormPanel UIObject Widget Frame NamedFrame
Widget : Hidden Un widget pour encapsuler un champ caché Permet de gérer le nom et la valeur du champ UIObject Widget Hidden
Widget : Hyperlink Un widget pour spécifier un hyperlien &quot;interne&quot; Un lien vers un &quot;état&quot; de l'application On y reviendra plus tard avec la gestion de l'historique Implémente HasText et HasHTML UIObject Widget Hyperlink
Interface HasDirection Indiquer qu'un widget possède son sens de lecture Propose les accesseurs getDirection() et setDirection() Enumeration Direction proposant les constantes LTR : lecture de gauche à droite RTL : lecture de droite à gauche DEFAULT : le sens de lecture naturel (hérité de son parent) Concerne les widgets textuels comme les Label
Interface HasWordWrap Marque un widget disposant de la propriété WordWrap Permet d'activer le passage à la ligne sans césure Propose les méthodes getWordWrap() et setWordWrap(boolean) Concerne les widgets textuels Label, HTML, Anchor, …
Interface HasAlignment Marque un widget avec alignement horizontal et vertical Hérite de l'interface HasHorizontalAlignment Classe interne HorizontalAlignmentConstant définit les constantes ALIGN_LEFT : alignement à gauche ALIGN_CENTER : alignement centré ALIGN_RIGHT : alignement à droite ALIGN_DEFAULT : alignement &quot;naturel&quot; (gauche si on lit de gauche à droite) Propose les accesseurs de la propriété &quot;horizontalAlignment&quot; Hérite de l'interface HasVerticalAlignment Classe interne VerticalAlignmentConstant définit les constantes ALIGN_BOTTOM : alignement en bas ALIGN_MIDDLE : alignement centré vertical ALIGN_TOP : alignement en haut Propose les accesseurs de la propriété &quot;verticalAlignment&quot;
Hiérarchie partielle (Label) UIObject Widget Label HTML InlineLabel InlineHTML
Widget : Label Un widget contenant du texte brut Implémente HasText (mais pas HasHTML) HasWordWrap HasDirection HasHorizontalAlignment Une sous classe InlineLabel ? Label utilise un élément <div> InlineLabel utilise un élément <span> produisant un layout en ligne UIObject Widget Label InlineLabel
Widget : HTML Un label contenant du texte HTML Hérite des interfaces de Label et ajoute HasHTML Comme pour Label, version &quot;inline&quot; HTML utilise un élément <div> InlineHTML utilise un élément <span> UIObject Widget HTML InlineHTML
Widget : Tree Un widget pour représenter une arborescence Implémente HasAnimation, HasFocus Contient des TreeItem Similaire au MenuBar et ses MenuItem TreeItem contient lui même un widget TreeItem : un texte et un &quot;UserObject&quot; Propose Méthodes addItem(TreeItem) et ses variantes avec String et Widget Méthodes remove(), removeItem(), removeItems(), clear() Méthodes iterator() et treeItemsIterator() : parcours des items Méthodes de gestion de la sélection UIObject Widget Tree
Widget : FileUpload Encapsule la fonctionnalité du navigateur L'utilisateur choisit un fichier local Fonctionnalité généralement sensible et protégée Seul moyen d’accéder au système de fichier Pas de valeur par défaut sur certains navigateurs Doit être intégré dans un formulaire avec un encoding multi-part Nécessite une partie serveur Pour recevoir le fichier UIObject Widget FileUpload
Hiérarchie partielle (FocusWidget) UIObject Widget FocusWidget Anchor ListBox SimpleCheckBox ButtonBase RichTextArea Button SimpleRadioButton TextBoxBase CheckBox CustomButton RadioButton PushButton ToggleButton TextArea TextBox PasswordTextBox
Interface HasFocus Marque un widget capable de gérer le focus Hérite de SourcesFocusEvent et SourcesKeyboardEvent Capable d'avoir des FocusListener et des KeyboardListener On verra plus tard la gestion des événements Propose de quoi gérer le focus et le tabIndex Méthode getTabIndex() : position dans la chaîne de tabulation Méthode setTabIndex(int index) : définir cette position Valeur -1 pour enlever le widget de la chaine Méthode setFocus(boolean) : prendre/laisser le focus Un seul widget peut avoir le focus, il prend alors tous les événements clavier Méthode setAccessKey(char) : raccourcis pour prendre le focus Combiner avec une touche spéciale (exemple Alt) pour prendre le focus
Widget : FocusWidget Racine des widgets capables de gérer le focus D'autres widgets implémentent aussi HasFocus Les widgets dans lesquels on peut saisir Les widgets manipulables au clavier Apporte aussi la notion &quot;enabled&quot; Propose les accesseurs isEnabled() et setEnabled() UIObject Widget FocusWidget
Interface HasName Marque un widget disposant d'un nom Propose les méthodes getName() et setName(String) Permet de l'utiliser dans un FormPanel Nom associé au widget quand le formulaire est soumis
Widget : Anchor Un widget représentant un ancrage Encapsule un élément <a> Implémente HasText HasHTML HasHorizontalAlignment HasWordWrap HasDirection HasName UIObject Widget FocusWidget Anchor
Widget : ButtonBase et Button Racine des widgets de type Bouton Traditionnellement les Button, CheckBox et RadioButton Implémente HasHTML Button Un bouton d'action On lui associe un ClickListener pour réagir au clic Méthode click() pour simuler programmatiquement le clic UIObject Widget FocusWidget ButtonBase Button
Widget : CheckBox, SimpleCheckBox Widget représentant une case à cocher Introduit une propriété &quot;checked&quot; Propose les accesseurs isChecked() et setChecked() Implémente HasName (utilisable dans un formulaire) CheckBox affiche son label Passé dans le constructeur SimpleCheckBox n'a pas de label UIObject Widget FocusWidget ButtonBase CheckBox SimpleCheckBox
Widget : RadioButton, SimpleRadioButton Des boutons exclusifs Doivent appartenir à un même &quot;groupe&quot; Le &quot;name&quot; hérité sert à définir le groupe L'indiquer dans le constructeur RadioButton affiche son label SimpleRadioButton n'as pas de label UIObject Widget FocusWidget ButtonBase CheckBox SimpleCheckBox RadioButton SimpleRadioButton
Widget : CustomButton Racine des boutons personnalisables Associer des images ou des textes Selon que le bouton est enfoncé ou non UIObject Widget FocusWidget ButtonBase CustomButton
Widget : PushButton Un bouton d'action personnalisable Permet de lui associer des images Permet de gérer le déroulement d'un clic Méthode onClickStart() : début du clic Méthode onClickCancel() : clic annulé Méthode onClick() : clic de l'utilisateur UIObject Widget FocusWidget ButtonBase CustomButton PushButton
Widget : ToggleButton Un CheckBox personnalisable Spécifier des images, le bouton peut rester enfoncé Méthodes pour gérer la sélection Méthode isDown() Méthode setDown() Méthode onClick() UIObject Widget FocusWidget ButtonBase CustomButton ToggleButton
Widget : TextBoxBase Racine des widgets de saisie textuelle Implémente HasText, HasName et HasFocus Introduit les propriétés &quot;readOnly&quot; : lecture seule &quot;cursorPos&quot; : position du curseur &quot;textAlignment&quot; : alignement du text Constantes ALIGN_[LEFT, CENTER, RIGHT, JUSTIFY] Accès au text sélectionné getSelectedText(), getSelectedLength(), selectAll(), setSelectionRange() Filtrage de la saisie setKey(char) : réception d'un caractère cancelKey() : refuser le caractère en cours de saisie UIObject Widget FocusWidget TextBoxBase
Widget : TextBox, PasswordTextBox Le champ de saisie standard Une seule ligne Implémente HasDirection en plus Introduit les propriétés &quot;maxLength&quot; : nombre maxi de caractères &quot;visibleLength&quot; : nombre visible de caractères PasswordTextBox Masque la saisie UIObject Widget FocusWidget TextBoxBase TextBox
Widget : TextArea Une zone de texte multi-lignes Implémente HasDirection en plus Introduit les propriétés &quot;visibleLines&quot; : nombre de lignes visibles &quot;characterWidth&quot; : longueur des lignes UIObject Widget FocusWidget TextBoxBase TextArea
Widget : RichTextArea Saisie de texte riche (HTML) Style et formatage Implémente HasText, HasHTML et HasFocus getText() : le texte brut sans formatage getHTML() : le texte HTML Intéressant de lui adjoindre une barre d'outil RichTextToolBar dans le Showcase (pas inclus de base) Copier la classe et les ressources du répertoire Répertoire com.google.gwt.sample.showcase.client.content.text UIObject Widget FocusWidget RichTextArea
Widget : ListBox (1) Liste de choix Items sont des String, gérés par leur indice Ajout des items avec addItem(String) Implémente HasName et HasFocus Propriété &quot;selectedIndex&quot; : indice sélectionné &quot;visibleItemCount&quot; : nombre de lignes &quot;multipleSelect&quot; : sélection multiple Méthode insertItem et removeItem (par indice) Méthode getItemCount() : nombre d'items Drop-down (combo) avec setVisibleItemCount(1) UIObject Widget FocusWidget ListBox
Widget : ListBox (2) Possibilité de distinguer item et sa valeur Méthode addItem(String item, String valeur) Méthode insert(String item, String value, int index) Accès getItemText(int) et getValue(int) Modification setItemText(int, String) et setValue(int, String) Insertion à l'indice, en fin si négatif ou trop grand Sélection multiple Obligation de parcours Méthode isItemSelected(int) Méthode setItemSelected(int, boolean) Différent de setSelectedItem(int) : sélection simple TP 5
La notion de layout Logique différente de Swing Difficile de mapper vers des éléments HTLM => approche différente GWT propose un ensemble de Panel Affichent de manière spécifique leurs widgets Exemples HorizontalPanel : widgets de gauche à droite FlowPanel : comme HTML, de gauche à droite mais passe à la ligne AbsolutePanel : positionnement absolu
Panel, Composite et HasWidgets Pattern &quot;composite&quot; classique dans les GUI Certains widgets contiennent d'autres widgets Permet d'assembler de manière récursive les interfaces Remarque : ce sont eux-mêmes des widgets (récursivité) Panel Classe naturelle pour effectuer un &quot;regroupement&quot; (plutôt layout) Composite Plutôt un widget complexe contenant déjà des widgets Propose de l'intéraction, ce que ne fait généralement pas le panel Interface HasWidgets Une interface pour marquer les widgets conteneurs
Interface HasWidgets Marque un widget qui peut contenir des widgets Hérite de Iterable qui propose la méthode iterator() Typiquement les Panel et les Composite Propose de quoi énumérer les widgets contenus Méthode add(Widget) Méthode remove(Widget) Méthode clear() : supprime tous les widgets Méthode iterator() : retourne un Iterator<Widget> sur les widgets Panel et Composite l'implémentent
Hiérarchie partielle (Panel) UIObject Widget Panel ComplexPanel HorizontalSplitPanel AbsolutePanel HTMLTable SimplePanel VerticalSplitPanel CellPanel DeckPanel FlowPanel HTMLPanel StackPanel RootPanel DockPanel HorizontalPanel VerticalPanel DecoratedStackPanel DecoratorPanel FocusPanel FormPanel PopupPanel ScrollPanel DecoratedPopupPanel DialogBox
Panel Racine des conteneurs de widgets Plutôt destiné au layout Implémente HasWidgets La hiérarchie de composition est accessible Tout widget connaît son conteneur parent En haut de la hiérarchie se trouve le RootPanel Nécessité de garantir l'intégrité de cette composition Gérée dans les méthodes add, remove et setWidget Nécessité de gérer l'attachement et le détachement UIObject Widget Panel
Panel : attachement et détachement (1) Fuite mémoire en JavaScript : problème classique Garbage Collector ne peut ramasser les références cycliques En particulier les gestionnaires d'événements (qu'on verra plus tard) Importance de nettoyer ces références cycliques (tâche rébarbative) GWT gère en proposant des méthodes à éventuellement redéfinir Widget conteneur  Widget contenu setWidget (ou add) adopt  ->setParent() onAttach() //positionne les listeners doAttachChildren() //propager à ses widgets onLoad() setWidget(avec null ou remove) orphan  ->setParent(null) onDetach() onUnload doDetachChildren() //propager à ses widgets //retire les listeners
Panel : attachement et détachement (2) Respecter quelques règles Appeler super.onAttach() si on redéfinit cette méthode Redéfinir doAttachChildren() si on implémente HasWidgets Ainsi que doDetachChildren() Plutôt redéfinir onLoad() et onOnload()
SimplePanel, ComplexPanel Contenir un seul ou plusieurs widgets SimplePanel Un seul widget : accesseurs get et setWidget() Ajout visuel autour du widget DecoratorPanel Ou regroupement de fonctionnement PopupPanel, FormPanel, ScrollPanel, … Ce widget contenu peut bien sûr être un Panel ComplexPanel Plusieurs widgets Permet le layout DeckPanel, FlowPanel, StackPanel, … UIObject Widget Panel SimplePanel UIObject Widget Panel ComplexPanel
Interface IndexedPanel Marque un panel aux widgets accessibles pas indice Implique un ordre explicite des widgets contenus Propose Méthode getWidgetCount() : nombre de widgets Méthode getWidget(int) : widget par son indice Méthode getWidgetIndex(Widget) : indice du widget Méthode remove(int) : enlever un widget Concerne la plupart des ComplexPanel
FlowPanel Organise ses widgets en lignes C'est le layout naturel de HTML Plusieurs lignes si pas assez large Implémente HasIndexedPanel Propose Méthode addWidget(Widget) Méthode insertWidget(Widget, index) UIObject Widget Panel ComplexPanel FlowPanel
CellPanel Dispose ses widgets dans une table Un widget par cellule Implémente HasIndexedPanel C'est une classe abstraite Propriétés &quot;spacing&quot; : espace entre les cellules &quot;borderWidth&quot; : épaisseur de bordure Dimension de cellule Méthodes setCellWidth(), setCellHeight() Alignement de cellule setCellHorizontalAlignment(), setCellVerticalAlignment() UIObject Widget Panel ComplexPanel CellPanel
HorizontalPanel, VerticalPanel Dispose ses widgets horizontalement Pas de retour à la ligne (différent de FlowPanel) Implémente IndexedPanel, HasAlignment Autorise aussi l'insertion Méthode insert(Widget, int) VerticalPanel dispose verticalement Sur une seule colonne UIObject Widget Panel ComplexPanel CellPanel HorizontalPanel
DockPanel Organise ses widgets dans des zones NORTH, SOUTH, EAST, WEST, CENTER Correspond au BorderLayout de Swing Implémente HasAlignment Méthode add(Widget, DockPanel.Direction) Chaque zone peut contenir plusieurs widgets On peut ajouter plusieurs widgets dans une zone NORTH et SOUTH subsidiaires s'empilent au milieu Deux autres constantes LINE_START et Line_END Gérer le sens de lecture plutôt que EAST-WEST UIObject Widget Panel ComplexPanel CellPanel DockPanel
Exemple DockPanel
DeckPanel Organise ses widgets en un tas Comme un tas de carte Un seul visible à la fois : showWidget(int) Ne pas confondre avec le DockPanel Implémente HasAnimation et HasIndexed C'est le panel interne utilisé par le TabPanel (onglet) Attention : impacte les dimensions de ses widgets Propose Méthode getVisibleWidget() : indice du widget montré Méthode showWidget(int) : montrer le widget indiqué Méthode insert(Widget, int) : insertion UIObject Widget Panel ComplexPanel DeckPanel
StackPanel Organise ses widgets en une pile verticale Un seul montré à la fois : showStack(int) Les autres représentés par un header sensible au click Implémente IndexedPanel Propose Méthode getSelectedIndex() : sélection Méthode showStack(int) : sélectionner Gestion des headers Méthodes addWidget(Widget, String) Méthode setStackText(int, String) Gestion des headers HTML Méthodes addWidget(Widget, String, boolean) Méthode setStackText(int, String, boolean) UIObject Widget Panel ComplexPanel StackPanel
DecoratedStackPanel Ajoute simplement une décoration Gestion de coins arrondis à l'aide d'images UIObject Widget Panel ComplexPanel StackPanel Decorated StackPanel
AbsolutePanel Positionnement absolu de ses widgets Widgets peuvent se chevaucher Implémente IndexedPanel Positionnement left et top Widgets gardent leurs dimensions Propose Méthode add(Widget, int, int) : ajouter en positionnant Méthode setWidgetPosition(Widget, int, int) Méthodes getWidgetLeft(Widget), getWidgetTop(Widget) Méthode addWidget(Widget) : ajouter en empilant verticalement RootPanel en hérite !!! UIObject Widget Panel ComplexPanel AbsolutePanel RootPanel
HTMLPanel Approche complètement différente Encapsuler du code HTML Attacher les widgets aux éléments identifiés de ce code Le layout est géré ailleurs (dans le code HTML) Implémente IndexedPanel Propose Constructeur acceptant le code HTML Méthode add(Widget, String) : ajoute le widget à l'élément identifié Méthode addAndReplaceElement(Widget, id) : ajoute et remplace Méthode createUniqueId() : helper pour créer des id uniques UIObject Widget Panel ComplexPanel HTMLPanel
HTMLTable Panel à base de cellules en colonnes Ne pas confondre avec HTMLPanel Widgets dans les cellules, coordonnées row, column Propose Propriété borderWidth : épaisseur de bordure Propriété cellPadding et cellSpacing : espace entre les cellules Méthodes d'accès général Méthodes clear(), clearCell(int, int) et remove(Widget) Méthodes getRowCount(), getCellCount(int), isCellPresent(int, int) Méthodes getWidget(int, int) : version avec Text et HTML Méthodes setWidget(int, int, Widget) : idem Méthodes d'accès aux formatters getColumnFormatter(), getRowFormatter(), getCellFormatter() UIObject Widget Panel HTMLTable
Grid Une table avec des dimensions prédéfinies Constructeur Grid(int numRow, int numColumn) Possibilité de redimensionner après coup : resize() Dimensions des rangées et colonnes Pas imposées et variables Largeur de colonne imposée par son widget le plus grand Hauteur de ligne imposée par son widget le plus large Idéal pour organiser dans une structure tabulaire UIObject Widget Panel HTMLTable Grid
FlexTable Une table flexible Permet de créer des cellules à la demande Un widget peut s'étaler sur plusieurs cellules Organisation logique en rangées de taille variable Propose Méthodes insertRow(int), removeRow(int) Méthodes getRowCount() et getCellCount(int) : cellules d'une row Méthodes insertCell, insertCells : insertion de cellules dans une row Accès au formateur avec getFlexCellFormatter() Permet de fusionner des cellules UIObject Widget Panel HTMLTable FlexTable
DecoratorPanel Ajouter une décoration autour d'un widget En général, le widget contenu est un panel La bordure est constituée d'images Neuf zones : les bords, les coins et le centre Permet de faire des coins arrondis Permet de redimensionner sans détruire le look Définies dans les styles (on verra plus tard) UIObject Widget Panel SimplePanel DecoratorPanel
PopupPanel Un panel qui &quot;surgit&quot; au dessus des autres Typiquement tooltip, menu, dialog Ne pas les ajouter à un panel : show() et hide() Dimensions déterminées par son widget contenu Méthodes setWidth() et setHeight() redirigées sur ce contenu Implémente HasAnimation Propriétés &quot;autoHide&quot; : se ferme tout seul (sur clic en dehors) &quot;modal&quot; : capture tous les événements des autres widgets Positionnement : setPopupPosition(), center(), … DecoratedPopupPanel : décore aussi le centre UIObject Widget Panel PopupPanel Decorated PopupPanel SimplePanel
DialogBox Les boîtes de dialogues Implémente HasText (le titre appelé &quot;Caption&quot;) Implémente HasHTML (le titre peut être HTML) SimplePanel donc setWidget(Widget) Renseigner son contenu avec un Panel En géréral ajouter des boutons de fermeture Invoquer la méthode hide() Mais &quot;autoHide&quot; et &quot;modal&quot; sont héritées Méthodes liées aux événements souris Méthodes onMouse[Enter,Move, Down, Up, Leave] Typiquement utiles pour la gestion d'un menu UIObject Widget Panel PopupPanel Decorated PopupPanel DialogBox SimplePanel
Exemple DialogBox
ScrollPanel Placer un widget dans une zone scrollable Affiche une partie de ce widget contenu Utilise des scrollbars pour représenter la partie visible Propose Propriété &quot;scrollPosition&quot; : la position verticale Propriété &quot;HorizontalScrollPosition&quot; : horizontale Méthodes pour scroller : scrollToBottom(), scrollToRight(), … Méthodes pour indiquer la dimension : setWidth(), setHeight() Méthode setAlwaysShowScrollBars() : masquer les scrollbars Méthode ensureVisible(UIObject) : scroll pour rendre visible UIObject Widget Panel ScrollPanel SimplePanel
HorizontalSplitPanel Dispose deux widgets horizontalement Barre de séparation permet de redimensionner Propose Propriétés &quot;leftWidget&quot; et &quot;rightWidget&quot; Propriétés &quot;startOfLineWidget&quot; et &quot;endOfLineWidget&quot; Méthode isResizing() : redimensionnement en cours ? Méthode setSplitPosition(String) : redimensionner UIObject Widget Panel Horizontal SplitPanel
VerticalSplitPanel Dispose deux widgets verticalement Barre de séparation permet de redimensionner Propose Propriétés &quot;bottomWidget&quot; et &quot;topWidget&quot; Méthode isResizing() : redimensionnement en cours ? Méthode setSplitPosition(String) : redimensionner UIObject Widget Panel Vertical SplitPanel
Intégrer GWT dans une page HTML On peut ajouter du code HTML dans la page Ressources dans le répertoire &quot;public&quot; sont copiées On peut les utiliser directement dans la page HTML Exemple ajout d'une image dans le <body> de la page <img src=&quot;images/logo.png&quot; /> Associer des RootPanel aux éléments de la page Nécessite que ces éléments soient identifiés (attribut id) RootPanel.get(&quot;xxx&quot;) TP 6
Hiérarchie partielle (Composite) UIObject Widget Composite CaptionPanel TabPanel DisclosurePanel SuggestBox DecoratedTabPanel TabBar DecoratedTabBar
Widget : Composite Racine des widgets &quot;composite&quot; Des widgets constitués de plusieurs parties Garder une certaine intégrité du composite Souvent pour construire ses propres widgets On en hérite et on compose avec des widgets existants En gérant spécifiquement les événements (qu'on verra plus tard) Toujours invoquer initWidget() dans le constructeur UIObject Widget Composite
Widget : CaptionPanel Cadre avec label autours d'un composant Le label peut être texte ou HTML Implémente HasWidgets Mais n'en contient qu'un seul Propose Propriétés &quot;captionText&quot; et &quot;captionHTML&quot; UIObject Widget Composite CaptionPanel
Widget : DisclosurePanel Contient &quot;header&quot; et widget escamotable Cliquer sur le &quot;header&quot; bascule la visibilité &quot;header&quot; peut être Widget ou String Implémente HasAnimation et HasWidgets Mais n'en contient qu'un seul Propose Propriété &quot;header&quot; (Widget) Propriété &quot;contents&quot; (Widget) Propriété &quot;open&quot; (boolean) UIObject Widget Composite DisclosurePanel
Widget : SuggestBox Un champs de saisie avec suggestion Propose dynamiquement une liste en cours de saisie Implémente HasText, HasAnimation, HasFocus Suggestions proviennent d'un SuggestOracle Une classe permettant de proposer une liste de suggestions Par défaut, MultiWordSuggestOracle Facile à renseigner : ajouter des string Propose Propriété &quot;text&quot; (vient du HasText) : le texte du champs Propriété &quot;suggestOracle&quot; : l'oracle qui va proposer les suggestions Propriété &quot;limit&quot; : limite le nombre de suggestions Méthode setPopupStyleName(String) : le style CSS du popup UIObject Widget Composite SuggestBox
Widget : TabBar, DecoratedTabBar Une barre d'onglets (utilisée avec TabPanel) Onglet de type texte, HTML ou Widget Sélection gérée par indice Propose Méthodes add et insert pour les 3 types Méthodes getTabCount() et removeTab(int) Méthodes getSelectedTab() et selectTab(int) Méthodes getTabText(int)  et setTabText(int, String) Méthodes getTabHTML(int) et setTabHTML(int, String) Méthodes pour gérer les événements DecoratedTabBar ajoute la décoration (coins arrondis) UIObject Widget Composite Decorated TabBar TabBar
Widget : TabPanel Gestion d'onglets Composite agrégeant un TabPanel et un DeckPanel Montre le widget associé à un &quot;tab&quot; Implémente HasAnimation, IndexedPanel, HasWidgets UIObject Widget Composite Decorated TabPanel TabPanel
Autres composants Projets open sources proposent d'autres widgets Calendrier, table triée, calculatrice, panel de dessin, bulle d'aide,… Widgets wrappant des librairies JavaScript existantes Google Map API Google Search API Scriptaculous Ext-GWT GWT-Ext SmartGWT Widget pour intégrer du SVG (Scalar Vector Graphics) Intégration de graphiques vectoriels
S'abstraire du JavaScript ? Philosophie générale mais pas toujours possible Besoin parfois d'intégrer des librairies ou des effets JavaScript Dangers de l’encapsulation de librairies JavaScript Sympa mais souvent un seul développeur Pas toujours bien développée ou adaptée à la philosophie GWT Exemple : arrêt du support GWT-Ext par le changement de licence de ext-js On retombe dans les problèmes de compatibilité de navigateur et de version Privilégier les librairies &quot;pures GWT&quot; Plutôt que les encapsulations de librairies JavaScript Garder à l’esprit que JavaScript = Assembleur du web Qui intègrerait des librairies en assembleurs dans ses applis ? Même dans le monde du jeu vidéo ça se fait de moins en moins
Gestion de l'i18n
Gestion de l’internationalisation Couvre plusieurs aspects Configuration de l'application Formatage des nombres et monnaies Traduction des messages et libellés L'approche de GWT est originale Ne pas gérer ces problèmes dynamiquement mais à la compilation Générer un fichier JavaScript pour chaque locale Technique récurrente de GWT : le &quot;DeferredBinding&quot;
DeferredBinding Technique pour pallier l'absence de &quot;dynamic binding&quot; En clair : pas de ClassLoader en JavaScript Implique de tout charger et utiliser ce qui convient Typiquement gestion des spécificités des navigateurs, des locales, … GWT gère autrement Fichier spécifique pour chaque navigateur et pour chaque locale Exemple : support de 5 navigateurs et 3 langues produit 15 fichiers différents On peut ajouter son propre axe de variance Exemple intranet / internet GWT gère automatiquement ces &quot;permutations&quot; En pratique : utiliser les méthodes de la classe GWT GWT.create(Interface) : obtenir une implémentation d'une interface
I18n : configuration Déclaration dans le fichier de description de module Déclarer une dépendance vers le module i18n Déclarer les locales supportées Test avec le mode &quot;Hosted&quot; Ajouter &quot;?locale=fr&quot; à la fin de l'URL Utiliser le bouton Go (Refresh ne convient pas) <module> <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.i18n.I18N'/> <extend-property name=&quot;locale&quot; value=&quot;fr&quot;/> … </module>
NumberFormat La classe pour formater des nombres et monnaies Méthode format(double) pour formater une valeur Méthode parse(String) pour décoder une chaîne Méthode statiques pour obtenir les formats standards Décimal : getDecimalFormat() Pourcent : getPercentFormat()  Scientifique getScientificFormat() Monnaie : getCurrencyFormat() Possibilité de construire son propre format (règles assez classiques) Méthode getFormat(String, String) (voir NumberFormat dans la javadoc) NumberFormat fmt1 = NumberFormat.getDecimalFormat(); double value1 = 12345.6789; String formatted = fmt1.format(value1); double value2 = fmt1.parse(&quot;12345.6789&quot;); NumberFormat fmt2 = NumberFormat.getFormat(&quot;000000.000000&quot;); formatted = fmt2.format(value1);
DateTimeFormat La classe pour formater les dates Méthodes format() pour formater une Date Méthode parse() pour décoder (s'accomode des dates invalides) Méthode parseStrict() pour décoder en refusant les dates invalides Variante pour modifier une Date existante Formats standards pour les Date, Time et DateTime getFullDateFormat(), getFullDateTimeFormat(), getFullTimeFormat() Variantes pour Long, Medium et Short Format spécifique avec getFormat(pattern) Règles classiques (voir DateTimeFormat dans javadoc)
Gestion des messages Similaire aux fichiers de properties Stoquer des strings et nombres dans des fichiers Y accéder depuis l'application Deux mécanismes Inclusion statique (à la compilation) Inclusion dynamique (à l'exécution)
I18n : interface Constants Déclarer une interface héritant de Constants Créer des méthodes d'accès à l'information Créer les fichiers .properties AppConstants.properties AppConstants_fr.properties Utiliser le DeferredBinding GWT.create() Implémentation à partir du fichier properties adéquat Autant de fichiers que de locales Penser à déclarer les locales Penser à écrire en UTF8 Plus simplement, utiliser le script i18nCreator Créer l'interface public interface MySettings extends Constants { String welcomeMsg();  String logoImage(); } Dans MySettings.properties welcomeMsg = Bonjour logoImage = /images/logo.jpg Utilisation dans le code MySettings s = GWT.create( MySettings.class); String msg = s.getWelcomeMsg();
I18n : interface ConstantsWithLookup Même principe mais ajoute une méthode de lookup Permet de rechercher dans les constantes Méthode getString(String) A éviter car ne permet pas le &quot;pruning&quot; C'est-à-dire la suppression des constantes non utilisées
I18n : interface Messages Même mécanisme mais avec des paramètres Hériter de l'interface Messages Option du i18nCreator Dans MySettings.properties welcomeMessage = Bonjour {0} {1} logoImage = /images/logo.jpg Interface correspondante public interface MySettings extends Constants { String welcomeMessage(String nom, String prenom);  String logoImage(); } Utilisation dans le code MySettings settings = GWT.create(MySettings.class); String msg = settings.getWelcomeMessage( login.getNom(), login.getPrenom());
(Dés)Avantages de l'inclusion statique Inclus dans le code compilé Aussi performant qu'une constante en dur Le compilateur optimise en faisant des &quot;inlines&quot; Seuls les messages utilisés sont embarqués Gros fichiers de propriétés institutionnels ne pénalisent pas l'appli Mais Génère beaucoup de fichiers si beaucoup de locales supportées Parfois on a besoin de valeurs plus dynamiques
I18n : inclusion dynamique Classe Dictionary N'utilise pas de fichier de propriétés Données dans le HTML, sous forme d'objet JavaScript Données ne sont plus fixées à la compilation mais au runtime Lecture par la méthode Dictionary.getDictionary(String) var MySettings = { welcomeMessage: &quot;Bienvenue&quot;, logoImage: &quot;/images/logo.jpg&quot; }; Dictionary settings = Dictionary.getDictionary(&quot;MySettings&quot;); TP 7
Les styles CSS
Les styles CSS (1) Rappel (pour plus d'info http://fr.selfhtml.org) Sert à séparer la présentation du contenu HTML (style) Forme : sélecteur { propriété: valeur }  CSS1 : environ 50 propriétés CSS2 : 70 de plus Selecteurs possibles <H1> => H1 { } <… class=&quot;grand&quot; …  => .grand { } <… id=&quot;titre&quot; … => #titre Peuvent se combiner : H1.grand = éléments H1 de classe &quot;grand&quot; Pseudo classe : exemple a.link = lien (balise <a>) pas encore visité H1 { text-align: center } .grand { font-size: 20pt } #titre { color: red } H1.grand { color: blue }
Les styles CSS (2) Peuvent se combiner pour plus de concision Regrouper des sélecteurs Regrouper des propriétés Héritage Styles des éléments englobants Sélectionner Séparer avec un espace H1, H2, H3 { font-style: bold } H1 { color: green; text-align: center; } --- <BODY> <H1>Un exemple</H1> <P>Avec un <STRONG>paragraphe</STRONG> </P> </BODY> --- /* bleu pour contenu du BODY */ BODY { color: blue } /* rouge pour STRONG dans P */ P STRONG { color: red }
Les styles CSS (3) Formatage d'écriture Plusieurs attributs Famille, Style, Variante Taille, Poids, Etirement Forme simplifiée Espace entre les valeurs Surcharge partielle Styles présents dans : HTML, fichiers CSS, config navigateur, préférences utilisateur Firefox + FireBug sont nos amis H1 { font-family: 'Times New Roman', serif; font-style: italic; font-variant: normal; font-size: large; font-weight: bold; font-stretch: expanded; } H2 { font: Times 13px bold; } H3 { font-weight: bold }
Style des widgets Méthode setStyleName() pour affecter un style Indiquer le nom du style en paramètre (String) Nécessite la présence du nom dans le fichier de styles Préfixé par &quot;.&quot; (oubli fréquent) Lien vers la feuille de styles Dans le HEAD du HTML : <link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot;> Ou plutôt dans le fichier module : <stylesheet src=&quot;styles.css&quot;/> Mieux car lié à l'appli et non au fichier HTML Dans le code :  Dans le fichier de styles : widget.setStyleName(&quot;special&quot;);  .special { float: right; margin: 5px; }
Style par défaut Chaque widget dispose d'un style spécifique Formé par convention : [projet]-[widget] Exemple : gwt-TextBox (style des boites de texte) Attention au préfixe &quot;.&quot; On peut modifier ces styles dans son fichier de styles Fichier public/App.css généré par l'applicationCreator
Thèmes Installation propose trois thèmes Standard, Chrome et Dark Configuré dans le fichier de description de module (&quot;App.gwt.xml&quot;) Existe en version RTL (lecture de droite à gauche) <inherits name=&quot;com.google.gwt.user.theme.dark.DarkRTL&quot;/> Ces thèmes produisent un fichier &quot;.css&quot; On le retrouve dans le répertoire gwt de l'appli compilé Exemple : gwt/standard/standard.css pour le thème standard C'est le fichier qui précise les styles par défaut
Modification du style UIObject propose des méthodes liées au style Méthode setStyleName(String) : permet d'affecter un style Remplace le style existant Utilisé comme une classe CSS => préfixe &quot;.&quot; dans les fichiers CSS L'intérêt des styles est de se combiner Pour combiner des effets graphiques, pour placer, … GWT propose 3 notions simplifiant cette combinaison Style primaire Style secondaire Style dépendant
Style primaire  La classe de style CSS pour un UIObject Chaque widget dispose de son style par défaut Forme &quot;gwt-&quot; suivi de la classe du widget (ex: gwt-Label) On peut changer ce style Avec setStylePrimaryName(String) Ou avec setStyleName(String) Subtile différence qu'on comprendra dans deux minutes
Style secondaire Un widget peut se voir affecter plusieurs styles Ajouter avec addStyleName(String) Supprimer avec removeStyleName(String) Séparation par un espace dans attribut class <… class=&quot;style1 style2&quot; …> Permet de combiner des effets dynamiquement Exemple : ajout d'une bordure rouge autour d'un widget en erreur
Style dépendant  Un style secondaire un peu spécial Caractérise une propriété, un état du composant Positionné avec addStyleDependentName(String) Ou plutôt avec des méthodes prévues (setReadonly()) Concatène le style primaire, un tiret et le style dépendant Exemple : .gwt-TextBox-readonly Style spécifique de boite de texte dans le cas readonly Conservé en cas de changement de style primaire Avec setStyleName => on efface tout Avec setStylePrimaryName => on renomme TP 8
Les styles CSS
Le modèle événementiel Navigateurs reçoivent les événements (clavier, souris) Puis les redirigent vers les éléments du DOM Deux modes possibles (bubbling ou capture) W3C impose aux navigateurs de respecter les 2 modes GWT masque et propose un modèle généralisé Document Elément2 Element1 Document Elément2 Element1 Event bubbling (modèle Internet Exporer) Event capture (modèle Netscape)
Event Représente un événement natif (du navigateur) Une classe &quot;opaque&quot; Encapsule un objet JavaScript Propose des constantes pour les types d'événement Propose des méthodes pour tester l'événement Propose quelques méthodes un peu spécifiques
Interface EventListener Ecouter les événements du navigateur Ceux qui arrivent sur les widgets via le DOM Seules les sous-classes de Widget devraient l'implémenter Le widget s'enregistre auprès du DOM Dans le onAttach() (vu précédemment) Méthode DOM.setEventListener(Element, EventListener) Doit déclarer le type d'événements qu'il consomme Méthodes sinkEvents() et unsinkEvents() Méthode onBrowserEvent(Event) C'est elle que les widgets vont redéfinir pour nous masquer tout ça
Interface EventPreview Listener pour &quot;prévisualiser&quot; les événements Capture les événèments et permet de les annuler Méthode onEventPreview(Event) : retourne false pour annuler Typiquement implémenté par les DialogBox Capturer les événéments sur les autres widgets Tant que le popup est ouvert Et les annuler Méthodes statiques de la classe Event Pour installer : Event.addEventPreview() Pour désinstaller : Event.removeEventPreview()
Schéma général SourcesConceptEvents -addConceptListener -removeConceptListener ConceptListener -onEtat1(…) -onEtat2(…) ConceptListenerCollection -fireEtat1(…) -fireEtat2(,…) ConceptListenerAdapter -onEtat1(…) { } -onEtat2(…) { } Widget Reçoit des Event du DOM, les retraduit en &quot;Concept&quot; en invoquant les &quot;fire&quot; MyListener1 -onEtat1(…) { … } -onEtat2(…) { … } MyListener2 -onEtat1(…) Interface Class implémente Class contient un Class hérite de Marque la capacité de contenir des listeners Simplifie la gestion de la collection de listeners en propageant les &quot;fire&quot; (invoque les &quot;on&quot;) Réagit aux événements Les méthodes reçoivent le widget en paramètre et éventuellement d'autres valeurs Marque un listener Simplifie si méthodes &quot;on&quot; nombreuses (implémentation vide) Ne redéfinit pas toutes les méthodes &quot;on&quot; Classe développée
Exemple avec Button et Click SourcesClickEvents -addClickListener -removeClickListener ClickListener -onClick(Widget) ClickListenerCollection -fireClick(Widget) Button MyClickListener() { public void onClick(Widget) {   Window.alert(&quot;Click !&quot;);   } } Pas de ClickListenerAdapter (une seule méthode dans l'interface)
Interface ClickListener Interface de listener d'un événement de type &quot;click&quot; Réagir à un clic sur le widget Propose la méthode onClick(Widget) Enregistrer auprès d'un SourcesClickEvents La plupart des widgets
Interface LoadListener Interface de listener pour un événement 'load' Typiquement chargement d'image Hérite de java.util.EventListener Réagir aux événements de chargement d'un widget Méthode onLoad(Widget) Chargement terminé avec succès Méthode onError(Widget) Chargement vient d'échouer Enregistrer auprès d'un SourcesLoadEvents Uniquement Image
Interface ChangeListener Interface de listener d'un événement de type &quot;change&quot; Réagir à une modification du widget Propose la méthode onChange(Widget) Enregistrer auprès d'un SourcesChangeEvents Typiquement les TextBox et les ListBox
Interface FocusListener Interface de listener d'un événement de focus Réagir à la prise ou perte de focus sur le widget Propose les méthodes onFocus(Widget) et onLostFocus(Widget) Enregistrer auprès d'un SourcesFocusEvents Les FocusWidget bien sûr mais aussi FocusPanel, SuggestBox, …
Interface KeyboardListener Interface de listener des événements clavier Réagir à l'enfoncement/relachement des touches du clavier Méthodes onKeyDown, onKeyPress, onKeyUp Recoivent le widget source, le caractère et le modificateur (ALT, SHIFT, CTRL) Constantes  KEY_UP, KEY_TAB, KEY_ENTER, KEY_ESCAPE, … MODIFIER_ALT, MODIFIER_CTRL, MODIFIER_META, MODIFIER_SHIFT  Enregistrer auprès d'un SourcesKeyboardEvents La plupart des widgets
Interface MouseListener Interface de listener des événements souris Réagir à l'enfoncement/relachement des boutons de la souris Réagir à l'entrée, survol, sortie de la souris dans la zone du widget Méthodes onMouseDown, onMouseUp, onMouseMove Reçoivent le widget source, les coordonnées x et y de la souris Méthode onMouseEnter, onMouseLeave Reçoivent seulement le widget Enregistrer auprès d'un SourcesMouseEvents Les Label, HTML, Image, …
Interface MouseWheelListener Interface de listener de la molette de la souris Réagir à l'utilisation de la molette de la souris Méthodes onMouseDown, onMouseUp, onMouseMove Reçoivent le widget source, les coordonnées x et y de la souris Méthode onMouseWheel(Widget, MouseWheelVelocity) Le MouseWheelVelocity contient les informations de direction et delta Enregistrer auprès d'un SourcesMouseWheelEvents Les Label, HTML, Image, …
Interface PopupListener Interface de listener spécifique des PopupPanel Réagir à la fermeture d'un popup (menu, dialog, …) Méthode onPopupClosed(PopupPanel, boolean) Reçoit le panel et un booléen &quot;autoClosed&quot; Le booléen indique si le popup s'est fermé automatiquement ou par programme Enregistrer auprès d'un SourcesPopupEvents PopupPanel et ses sous-classes (dont DialogBox)
Interface ScrollListener Interface de listener spécifique des ScrollPanel Réagir au déplacement des barres de défilement Méthode onScroll(Widget, int, int) Reçoit le widget et les positions horizontale et verticale Enregistrer auprès d'un SourcesScrollEvents ScrollPanel uniquement
Interface TabListener Interface de listener spécifique des TabPanel et TabBar Réagir à la sélection d'un onglet Méthodes onTabSelected et onBeforeTabSelected Reçoivent le SourceTabEvents et l'indice de l'onglet concerné par la sélection Enregistrer auprès d'un SourcesTabEvents TabPanel uniquement
Interface TableListener Interface de listener spécifique des tables Réagir à la sélection d'une cellule de la table Méthodes onCellClicked(SourcesTableEvents, int, int)  Reçoivent le SourceTabEvents et les coordonnées de la cellule  Enregistrer auprès d'un SourcesTabEvents HTMLTable et ses sous-classes (Grid et FlexTable)
Interface TreeListener Interface de listener spécifique des arbres (Tree) Réagir à la sélection ou changement d'état d'un TreeItem Méthodes onTreeItemSelected et onTreeItemStateChanged Reçoivent le TreeItem concerné Enregistrer auprès d'un SourcesTreeEvents Tree uniquement TP 9
Communications serveurs
Echange de données Nécessité d'échanger des données avec le serveur Chercher des données à afficher Transmettre des informations d'identification (login, password) Transmettre des données Sans nécessiter un raffraichissement de toute la page Comme le ferait un formulaire traditionnel Plusieurs technologies possibles Standard JavaScript : objet XMLHttpRequest RequestBuilder : une classe qui encapsule XMLHttpRequest GWT-RPC : échanger directement des objets Java
Requête asynchrone Principe fondamental d'Ajax Asynchronous JavaScript And XML Ne bloque pas le navigateur Permet de faire autre chose en attendant (préparer l'affichage) Nécessite une structure d'appel particulière On ne peut pas faire un appel synchrone (appel de méthode) Mécanisme de &quot;Callback&quot; Code invoqué lorsque l'appel se termine (ou échoue) C'est un mécanisme événementiel
RequestBuilder Encapsule l'objet XMLHttpRequest de JavaScript Plus proche du Java dans son utilisation Définit  Des constantes pour les types de requête (GET, POST, …) Un constructeur (type de requête + une url) Une méthode de construction de requête (pattern &quot;builder&quot;) Prend une string (paramètres) et un RequestCallback (gestionnaire de réponse) Lance la requête (de manière asynchrone) Retourne un objet Request
Interface Request Requête asynchrone Permet de ne pas bloquer le navigateur Attention : navigateurs limitent généralement le nombre de requêtes Objet Request permet de vérifier le status de la requête Intéressant dans le cas de requête longue Ou même de l'annuler
Interface RequestCalback Définir un gestionnaire de réponse pour la requête Gestion événementielle car requête asynchrone Propose Méthode onResponseReceived() : gérer la réponse Méthode onError() : gérer une erreur En général, créer une classe interne anonyme Implémentant l'interface Exactement similaire à la gestion d'événement avec Swing Multiples formats de réponse possibles XML, HTML, texte brute, JSON, …
Exemple d'appel avec RequestBuilder String url = &quot;/service/search&quot;; RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url); try { Request request = rb.sendRequest(&quot;param=arg&quot;, new RequestCallBack() { public void onResponseReceived(Request req, Response rep) { //traitement de la réponse } public void onError(Request req, Throwable exception) { //gestion d'erreur } }); } catch (RequestException e) { //gestion d'exception } TP 10
XMLParser Importance de XML dans les échanges de données Format textuel (&quot;lisible&quot; par l'homme et la machine) Décrit et validable (DTD, schéma) GWT fournit un XMLParser Ajouter dépendance <inherits name=&quot;com.google.gwt.xml.XML&quot; /> Délègue le parsing au navigateur (efficacité car code natif) Produit un DOM (Document Object Model) Et des méthodes pour naviguer Document doc = XMLParser.parse(responseText); Element root = doc.getDocumentElement(); NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { traiter(children.item(i); } TP 11
Impact des comm. asynchrones Améliore l'expérience utilisateur Rafraîchissement rapide de morceaux de page Remplissage dynamique de listes longues, d'arbre Rafraîchissement automatique possible … Techniquement Nécessite un codage / décodage des données Parsing et constitution des DOM (empreinte mémoire importante)
Service GWT RPC Echanger directement des objets Permet de masquer cette phase de décodage La partie serveur est en Java et y reste (tout est possible) Plusieurs étapes Définir une interface du service Définir une implémentation du service (servlet) Définir une interface d'appel asynchrone Déclarer le servlet dans le fichier module Créer un invocateur du service (proxy) Configurer cet invocateur vers le servlet Créer un AsyncCallback pour gérer la requête Invoquer le service
Mise en œuvre d'un service  (1) Première étape : définir l'interface du service Doit hériter RemoteService Doit être dans le sous-package &quot;.client&quot; de l'application Contraintes fortes sur paramètres et valeur de retour Voir ci-après Sérialisation En bref : primitifs, String, Date, Serializable, Array et IsSerializable package com.oxiane.formation.cave.client; import com.google.gwt.user.client.rpc.RemoteService; //MyData et MyParam sont des POJOs Serializable public interface MyService extends RemoteService { MyData[] myRemoteMethod(MyParamData paramData); }
Mise en œuvre d'un service  (2) Définir une implémentation du service (servlet) Doit hériter RemoteServiceServlet Doit être dans le sous-package &quot;.server&quot; de l'application Doit implémenter l'interface du Service Doit être nommée comme le Service suffixé avec Impl Le code est complètement libre (reste sur le serveur) package com.oxiane.formation.cave.server; import com.google.gwt.user.server.rpc.RemoteServiceServlet; … import com.oxiane.formation.cave.client.MyService; public class MyServiceImpl extends RemoteServiceServlet implements MyService { public MyData[] myRemoteMethod(MyParamData paramData) { … return result; } }
Mise en œuvre d'un service  (3) Déclarer une interface d'appel asynchrone Nécessaire pour rester dans la logique Ajax Doit porter le même nom que l'interface suffixée avec &quot;Async&quot; Doit reprendre les méthodes de l'interface (pas tout à fait) Paramètre supplémentaire de type AsyncCallback<typeRetour> Type de retour void Type de retour reporté dans le type générique du AsyncCallback Attention : contraintes non explicites !!! package com.oxiane.formation.cave.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface MyServiceAsync { void myRemoteMethod(MyParamData paramData,   AsyncCallback<MyData[]> callback); }
Mise en œuvre d'un service  (4) Déclaration du servlet Dans le fichier module pour tester avec le mode hosted Dans le fichier web.xml en déploiement réel Remarque le chemin est libre <servlet path='/myservice' class='com.oxiane.formation.cave.server.MyServiceImpl'/>
Mise en œuvre d'un service  (5) Créer un invocateur du service Il s'agit d'un proxy implémentant l'interface Async Utilise le &quot;DeferredBinding&quot; : GWT.create(MyService.class) Remarque Interface de retour est différente de celle demandée Idéalement le conserver en attribut pour plusieurs utilisations MyServiceAsync myServiceProxy = GWT.create( MyService.class );
Mise en œuvre d'un service  (6) Configurer le proxy Il faut le lier au servlet par l'URL Interface ServiceDefTarget GWT.getModuleBaseURL () pour obtenir l'URL Possibilité d'automatiser avec une annotation sur l'interface @RemoteServiceRelaticePath(&quot;chemin du service&quot;) Bien mettre le même chemin que dans le fichier module ((ServiceDefTarget) myServiceProxy).setServiceEntryPoint ( GWT.getModuleBaseURL () + &quot;/myservice&quot;  );
Mise en œuvre d'un service  (7) Créer un gestionnaire de réponse (AsyncCallback<T>) Interface de callback Méthode onSuccess(Object result) Méthode onFailure(Throwable cause) Type générique apporte le type sur le paramètre du &quot;onSucces&quot; Comme d'habitude, on peut faire une classe anonyme AsyncCallback<MyData[]> callback = new AsyncCallback<MyData[]>() { public void onSuccess( MyData[] result ) { //code en cas de succès } public void onFailure( Throwable caught ) { //code en cas d'erreur } };
Mise en œuvre d'un service  (8) Invoquer le service Utiliser directement les méthodes de l'interface Async AsyncCallback<MyData[]> callback = new AsyncCallback<MyData[]>() { … }; MyParamData param = new MyParamData(1); myServiceProxy.myRemoteMethod(param, callback);
Sérialisation (1) Encoder et décoder les objets Intérêt de GWT-RPC = masquer cette phase (le plus possible) Contrainte sur les données sérialisables Types primitifs char, byte, short, int, long, boolean, float et double Leur wrapper Character, Integer, … String, Date Enumeration (mais seul leur nom est sérialisé) Les classes implémentant com.google.gwt.user.client.rpc.IsSerializable Ou java.io.Serializable (depuis GWT 1.5) Les collections et arrays de ces types
Serialisation (2) Remarques sur les classes sérialisables Avoir un constructeur vide Mot clé &quot;transient&quot; respecté (attribut ignoré) Attributs &quot;final&quot; aussi (les marquer &quot;transient&quot; pour ne pas l'oublier) Problèmes avec les Collection telles que List et Set Nécessité de typer complètement Typage dans les commentaires dans les versions précédentes Exemple @gwt.typeArgs <java.lang.String> Utiliser les types génériques depuis 1.5 Exemple : Set<String>
Gestion des exceptions Sérialisables aussi si contraintes respectées Services peuvent lever des exceptions Méthode AsyncCallback.onFailure() pour gérer côté client InvocationException Levée si le client ne peut pas contacter le service Ou si un problème inattendu survient IncompatibleRemoteServiceException Si le service est modifié sans que le client soit au courant Recharger la page dans ce cas TP 12
Le format JSON Un format textuel courant dans le monde JavaScript Syntaxe JavaScript correspondant à la définition d'objets Facile à utiliser Site &quot;http://www.json.org&quot; Nombreux codeur/décodeur dans différents langages Deux modes d'utilisation dans GWT L'utiliser directement dans JavaScript (JSNI) Utiliser JSONParser et la hiérarchie des JSONValue
JSON : Grammaire
Utilisation de JSON Données textuelles en réponse d'une requête HTTP Analyser avec JSONParser.parse() Retourne une JSONValue (hiérarchie de classes) Propose des méthodes pour décortiquer la structure obtenue Exemple de données JSON { &quot;product&quot;: { &quot;name&quot;: &quot;Widget&quot;, &quot;company&quot;: &quot;ACME, Inc&quot;, &quot;partNumber&quot;: &quot;7402-129&quot;, &quot;prices&quot;: [ { &quot;minQty&quot;: 1, &quot;price&quot;: 12.49 }, { &quot;minQty&quot;: 10, &quot;price&quot;: 9.99 }, { &quot;minQty&quot;: 50, &quot;price&quot;: 7.99 } ] } }
JSONValue Classe abstraite Une sous classe pour chaque type de données JSON JSONArray, JSONBoolean, JSONNull, JSONNumber, JSONObject, JSONString Méthode isXXX() pour chaque type Attention : pas une méthode de test Retourne un objet de ce type si la value est bien de ce type Retourne null sinon Méthode toString Pour obtenir une string JSON prête à envoyer
JSONObject et JSONArray JSONObject Représente un objet JSON (une structure nom-valeur) Méthodes get(String) et set(String, JSONValue) Pour obtenir et positionner une valeur JSON par son nom Méthode size() : nombre de clés Méthodes keySet(), containsKey() Obtenir les clés et tester la présence d'une clé JSONArray Représente un tableau Méthodes get(int) et set(int, JSONValue) Pour obtenir et positionner une valeur JSON par son indice Méthode length() : longueur du tableau TP 13
Le bouton &quot;back&quot; du navigateur Problème avec le remplacement partiel de la page Ne compte pas comme un changement de page pour le navigateur Mais l'utilisateur voit une page différente Intuitivement, l'utilisateur peut vouloir annuler En utilisant le bouton &quot;back&quot; Pas agréable de condamner le bouton back Et ne marche pas bien Solution : gérer intelligemment le bouton &quot;back&quot;
Classe History (1) Générer des &quot;history token&quot; Pour identifier les états de l’application Par programmation History.newItem(&quot;accueil&quot;) Ou avec la classe Hyperlink Qui génère pour nous les tokens Gère des HistoryListener Méthode addHistoryListener()
Classe HistoryListener Interface pour réagir aux boutons Back et Forward Propose une méthode onHistoryChanged() Reçoit le token en paramètre Pour remettre l’application dans l’état correspondant au token Invoquée lors de l’utilisation des boutons Créer en général une implémentation anonyme
Fonctionnement de l’History Gestion transparente d'un &quot;frame&quot; caché html Doit être laissé dans la page HTML Le navigateur recharge le contenu du frame caché Il &quot;voit&quot; un chargement de page, l'ajoute dans son historique Le listener est sollicité (méthode onHistoryChanged()) L'application réagit en conséquence en fonction du token Pas de magie C’est au développeur de prendre en compte la cohérence Par exemple annuler des données soumises TP 14
Notions avancées
Log Problème récurrent avec les applications Web Non Ajax : toute action se passe sur le serveur => log possible Ajax : beaucoup d'actions mais impossible d'écrire sur un fichier On pourrait utiliser un service du serveur Besoin des log pour la mise au point Il existe des loggers JavaScript (intégration possible) Moins nécessaire avec mode Hosted (debug directement en Java) Possibilité d'utiliser le système de log du mode Hosted GWT.log() avec un message et un Throwable (ou null)
Utilisation d’images Widget pour afficher une image Indiquer l'URL complète ou bien relative au répertoire public Mode unclipped : image affichée en entier Mode clipped : image affichée partiellement Spécifier des coordonnées à la construction Source d'événements  Click, Load, Mouse et MouseWheel Permet d'abonner des listeners pour réagir Méthode statique prefetch() pour optimiser Demander au navigateur de pré-charger l'image
ImageBundle Problèmes avec le chargement de nombreuses images Chaque image recherchée coûte un appel vers le serveur Problème de bande passante Limitation du nombre de connexions simultanées vers le serveur Technique d'optimisation : regrouper les images En une seule grande image Permet de rapatrier la grosse image en un seul appel au serveur Possible car on peut afficher une partie d'une image ImageBundle simplifie cette technique
Mise en œuvre de ImageBundle Même principe que Constants : faire une interface Hériter de ImageBundle Déclarer des méthodes AbstractImagePrototype xyz(); Mettre le fichier image dans le répertoire de l'interface Extensions supportées automatiquement : .png, .gif ou .jpg Utiliser le DeferredBinding (GWT.create(MesImages.class) Récupérer les prototypes avec les méthodes xyz() Créer l'image avec la méthode createImage()
Intégration Java EE Limitation de JavaScript Interdiction d’adresser un autre site que celui d’origine Une sécurité dans les navigateurs pour éviter le code malicieux Impossible d’adresser des requêtes JEE vers un autre serveur Implique de passer par un proxy sur son serveur Le JavaScript appelle son serveur qui fera le relai
Déployer son application Essentiellement reconstituer un fichier WAR Avec l’application compilée bien sûr Copier les fichiers du répertoire www dans un répertoire temporaire Recréer la structure de répertoire WEB-INF et créer le web.xml Pensez à ajouter le code serveur dans le cas GWT RPC Compiler les servlets avec javac, copier et déclarer dans le web.xml En accord avec les url indiquées pour les proxy GWT RPC Copier le gwt-servlet.jar dans le WEB-INF/lib Zipper et renommer en .war En général, utilisation d’un script Ant pour faire tout ça
Tester avec Junit (1) Test = démarche de génie logiciel importante Améliore les garanties de succès pour un projet Intégration de JUnit dans GWT Pas de nécessité de développer des outils de test spécifiques Permet de tester ses objets et méthodes Permet de tester les appels RPC et leurs résultats Dans les deux modes (hosted et web) Mise œuvre Faire une sous-classe de GWTTestCase Une sous-classe de TestCase de junit Implémenter la méthode getModuleName() Le script junitCreator permet d’automatiser ça
Tester avec Junit (2) Création du TestCase Création des scripts de lancement Reste plus qu’à coder ses méthodes de tests Méthodes standards de JUnit junitCreator -junit &quot;C:\junit.jar&quot; -module com.google.gwt.sample.stockwatcher.StockWatcher -eclipse StockWatcher   com.google.gwt.sample.stockwatcher.client.StockWatcherTest TP 16
Présentation de JSNI Ecrire des méthodes natives en JavaScript Méthode java native Commentaire /*- -*/ pour spécifier le code Code recopié par le compilateur Permet aussi de Typer des méthodes JavaScript Appeler du code JavaScript depuis Java et vice versa Lire et écrire des attributs Java depuis JavaScript public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
Manipulation d'objets Java (1) JSNI permet d’invoquer du code Java Mais problème de typage Notation pour spécifier les méthodes et les types Invocation de méthode [instance-expr.]@class-name::method-name(param-signature)(arguments) Avec  [instance-expr.]  = Nom d’attribut ou this ou rien pour statique Signatures des paramètres suivent les règles JNI (voir ci après) Accès à un attribut [instance-expr.]@class-name::method-name
Manipulation d’objets Java (2) Syntaxe JNI des signatures de méthode Signature  Type Java ============================================ Z  boolean B  byte C  char S  short I  int J  long F  float D  double L nom/complet/de/classe;  classe  [ type  type[] Exemple  public class JSNIExample { void a(String s) { // code Java } } Invoqué en JavaScript avec this.@com.oxiane.JSNIExample::a(Ljava/lang/String;)(s);
Passage d’objets entre les deux mondes Les types primitifs passent sans problème Sauf long qui n’est pas supporté par JavaScript Objet JavaScriptObject Objet opaque pour le monde Java Ne peut être utilisé que par JavaScript (en le passant en argument) Objet Java Objet opaque pour le monde JavaScript
JavaScript Overlay Type  Technique pour encapsuler un objet JavaScript Dans une classe Java Plus facile à utiliser par le monde Java Définir une sous-classe de JavaScriptObject Avec un constructeur sans argument protected Des méthodes natives pour accéder aux infos de l’objet On peut même rajouter des vraies méthodes java Définir des méthodes statiques natives Dans d’autres classes Retournent des instances
GWTShell La classe qui lance le mode &quot;hosted&quot; L'applicationCreator génère un script &quot;App-shell&quot; GWTShell [-port numPort | &quot;auto&quot;] execute un tomcat sur le port (défaut 8888) [-noserver]  pas de serveur (si serveur externe utilisé)  [-whitelist &quot;list&quot;]  URLs externes autorisées (liste de regex) [-blacklist &quot;list&quot;]  URLs externes interdites (liste de regex) [-logLevel niveau]  ERROR, WARN, INFO*, TRACE, DEBUG, SPAM ou ALL [-gen répertoire]  répertoire des fichiers temps de compilation [-out répertoire]  répertoire de sortie des fichiers [-style style]  OBF[USCATED]*, PRETTY ou DETAILED  [-ea]  active la vérification des assertions [url]  URL à lancer expressions régulières séparées par &quot; &quot; ou &quot;,&quot; ^http[:][/][/]www[.]site[.]com * = Valeur par défaut
GWTCompiler La classe qui compile en JavaScript L'applicationCreator génère un script &quot;App-compile&quot; GWTCompiler [-logLevel niveau]  ERROR, WARN, INFO*, TRACE, DEBUG, SPAM ou ALL [-gen répertoire]  répertoire des fichiers temps de compilation [-out répertoire]  répertoire de sortie des fichiers [-treeLogger]  log sous forme arborescente [-style style]  OBF[USCATED]*, PRETTY ou DETAILED  [-ea]  active la vérification des assertions [-validateOnly]  valide le code source sans compiler module  nom du module à compiler * = Valeur par défaut
Exemple de JavaScript Overlay Données JSON obtenues en JavaScript var jsonData = [ { &quot;FirstName&quot; : &quot;Jimmy&quot;, &quot;LastName&quot; : &quot;Webber&quot; }, { &quot;FirstName&quot; : &quot;Alan&quot;,  &quot;LastName&quot; : &quot;Dayal&quot; }, ]; class Customer extends JavaScriptObject { protected Customer() { }  public final native String getFirstName() /*-{ return  this.FirstName; }-*/; public final native String getLastName()  /*-{ return  this.LastName;  }-*/; public final String getFullName() { return getFirstName() + &quot; &quot; + getLastName();  } } Dans une autre classe private native Customer getFirstCustomer() /*-{ return $wnd.jsonData[0];  }-*/; TP 17
Evolutions de la 1.6 (1) Nouvelle version 1.6 sortie Q1 2009 Accélérer la compilation (problème récurrent) Bénéficier des architectures multicores pour paralléliser la compilation Changement de structure des projets Structure WAR pour simplifier le déploiement Impact sur les outils Jetty à la place du tomcat embarqué (plus léger, plus rapide) Nouveau modèle événementiel à base de Handler Tous les listeners vont être remplacés par des Handler Impact sur le code existant Prise en compte des spécificités des chaînes de caractères (optim) Différence de performance sur les join, concat et += selon les navigateurs
Evolutions de la 1.6 (2) Suite GWT.runAsync : découper une appli en plusieurs fichiers Devenait nécessaire pour le développement de grosses applications Mode &quot;hosted&quot; Out-of-process : directement dans le navigateur UIBinder : charger des descriptions XML d'écrans plutôt que coder ClientBundle : regrouper des ressources spécifiques à un client Amélioration du support des outils de Mapping Objet Relationnel
Conclusion
Conclusion Un toolkit puissant et original Une approche différente du web Des techniques très bien pensées Optimisation systématique Disponibilités croissantes de bibliothèques Mais Encore en évolution Attention au choix des bibliothèques Trop puissant ?

Contenu connexe

PPTX
Les apports d'HTML5 pour l'interopérabilité des applications géospatiales
PPT
Introduction aux Technologies Web élaborée par Marouan OMEZZINE
PPTX
HTML 5 et CSS3, créez, animez et enrichissez vos sites Web
PPTX
USI 2009 - Du RIA pour SI
PDF
Livre blanc Windows Azure et les éditeurs de logiciel
PDF
Ter Web Service Intro
PDF
Jsf 110530152515-phpapp01
PDF
Ajax en Java - GTI780 & MTI780 - ETS - A09
Les apports d'HTML5 pour l'interopérabilité des applications géospatiales
Introduction aux Technologies Web élaborée par Marouan OMEZZINE
HTML 5 et CSS3, créez, animez et enrichissez vos sites Web
USI 2009 - Du RIA pour SI
Livre blanc Windows Azure et les éditeurs de logiciel
Ter Web Service Intro
Jsf 110530152515-phpapp01
Ajax en Java - GTI780 & MTI780 - ETS - A09

Tendances (20)

PDF
Traitement distribue en BIg Data - KAFKA Broker and Kafka Streams
PPTX
Presentation JEE et son écossystéme
PDF
Windows Azure, plongée en eaux profondes (300)
PDF
Flex, une techno RIA incontournable pour les futures app web ?
PPTX
BreizhCamp - Drupal7 dans le cloud avec Azure
PDF
Panel de solutions javascript
PPTX
JavaScript aussi sur le serveur et jusque dans le cloud?
PPTX
Axis2 services fr
PPTX
Server Side Javascript in the cloud
PPTX
Ejb3 3-message-driven-beans fr
PDF
Support JEE Servlet Jsp MVC M.Youssfi
PDF
Dotnet j2 ee
PDF
eServices-Tp1: Web Services
PPT
Présentation WPF
PDF
Services web soap-el-habib-nfaoui
DOCX
comment realiser un Service Web
PDF
Ajax en Java - GTI780 & MTI780 - ETS - A08
PPTX
Ejb3 2-session-beans fr
PPT
Environnements & Développements
DOCX
CV_Youssouph_BARRY_DRUPAL
Traitement distribue en BIg Data - KAFKA Broker and Kafka Streams
Presentation JEE et son écossystéme
Windows Azure, plongée en eaux profondes (300)
Flex, une techno RIA incontournable pour les futures app web ?
BreizhCamp - Drupal7 dans le cloud avec Azure
Panel de solutions javascript
JavaScript aussi sur le serveur et jusque dans le cloud?
Axis2 services fr
Server Side Javascript in the cloud
Ejb3 3-message-driven-beans fr
Support JEE Servlet Jsp MVC M.Youssfi
Dotnet j2 ee
eServices-Tp1: Web Services
Présentation WPF
Services web soap-el-habib-nfaoui
comment realiser un Service Web
Ajax en Java - GTI780 & MTI780 - ETS - A08
Ejb3 2-session-beans fr
Environnements & Développements
CV_Youssouph_BARRY_DRUPAL
Publicité

En vedette (20)

PDF
Guide Entrepreneur 2.0
PPTX
Food substitution | AIFST Annual conference 2015
PDF
Food adulteration
PDF
XIMEA Presentation by Max Larin: HSI Cameras for Food Safety and Fraud Detect...
PPTX
Anesthetic management of hyperthyroid patient posted for elective
PPTX
FOOD ADULTERATION Prasad ppt1
PPTX
Food adulteration
PDF
MSU Food Fraud Initiative Emering Issues & New Frontiers for FDA Regulation_2014
PDF
Digital RNAseq Technology Introduction: Digital RNAseq Webinar Part 1
PDF
Food adulteration
PDF
Food Fraud - Threats & Impacts
PDF
Economically Motivated Adulteration
PPTX
Nias nagas presentar
PDF
PUESTA EN MARCHA DE LAS NORMAS INTERNACIONALES DE AUDITORIA
PDF
Evolución normativa en España hasta las NIAS
PDF
Quick Start Guide Minelab GPX-4000 Metal Detector French Language 4901 0060 ...
PDF
Instruction Manual Minelab GPX 4800-5000 Metal Detector French Language ...
PDF
Treasury Web Report
PDF
Repères et Outils pour l’Évaluation de l’Aptitude au Contact Alimentaire de M...
PPTX
Nias
Guide Entrepreneur 2.0
Food substitution | AIFST Annual conference 2015
Food adulteration
XIMEA Presentation by Max Larin: HSI Cameras for Food Safety and Fraud Detect...
Anesthetic management of hyperthyroid patient posted for elective
FOOD ADULTERATION Prasad ppt1
Food adulteration
MSU Food Fraud Initiative Emering Issues & New Frontiers for FDA Regulation_2014
Digital RNAseq Technology Introduction: Digital RNAseq Webinar Part 1
Food adulteration
Food Fraud - Threats & Impacts
Economically Motivated Adulteration
Nias nagas presentar
PUESTA EN MARCHA DE LAS NORMAS INTERNACIONALES DE AUDITORIA
Evolución normativa en España hasta las NIAS
Quick Start Guide Minelab GPX-4000 Metal Detector French Language 4901 0060 ...
Instruction Manual Minelab GPX 4800-5000 Metal Detector French Language ...
Treasury Web Report
Repères et Outils pour l’Évaluation de l’Aptitude au Contact Alimentaire de M...
Nias
Publicité

Similaire à Google Web Toolkit 1.5 Presentation Web Creative Common (20)

PDF
Gwt oxiane-novae-lr
PPTX
Chapitre 1_Introduction_generale_sur JEE.pptx
PPT
GWT Principes & Techniques
KEY
Introduction aux RIA (Rich Internet Applications)
PDF
TP GWT JDEV 2015
PDF
FinistJUG - J’ai besoin d’une appli web rapidement
PDF
Introduction à GWT - GTI780 & MTI780 - ETS - A08
PDF
Présentation GWT au JUG Montréal 14 avril 2011
PDF
Gwt présentation-jug-14avr2011
PDF
Gwt
PDF
Gwt intro-101
PDF
cours-gratuit.com--id-1964.pdf
PPTX
API Servletcourensatangerpourlesetudiantsdu2emeanneeecole.pptx
PDF
Introduction à GWT - GTI780 & MTI780 - ETS - A09
PDF
GWT Approfondissement - GTI780 & MTI780 - ETS - A08
PDF
chapitre 1 4SAMIMNIFENETCOMMMMMMMMMMMMMMMMM.pdf
PPT
PDF
ENIB 2013-2014 - CAI Web #3: J’ai besoin d’une appli web rapidement
PPTX
JavaScript aussi sur le serveur et jusque dans le cloud?
PDF
J2eeintro
Gwt oxiane-novae-lr
Chapitre 1_Introduction_generale_sur JEE.pptx
GWT Principes & Techniques
Introduction aux RIA (Rich Internet Applications)
TP GWT JDEV 2015
FinistJUG - J’ai besoin d’une appli web rapidement
Introduction à GWT - GTI780 & MTI780 - ETS - A08
Présentation GWT au JUG Montréal 14 avril 2011
Gwt présentation-jug-14avr2011
Gwt
Gwt intro-101
cours-gratuit.com--id-1964.pdf
API Servletcourensatangerpourlesetudiantsdu2emeanneeecole.pptx
Introduction à GWT - GTI780 & MTI780 - ETS - A09
GWT Approfondissement - GTI780 & MTI780 - ETS - A08
chapitre 1 4SAMIMNIFENETCOMMMMMMMMMMMMMMMMM.pdf
ENIB 2013-2014 - CAI Web #3: J’ai besoin d’une appli web rapidement
JavaScript aussi sur le serveur et jusque dans le cloud?
J2eeintro

Plus de Stéphane Liétard (7)

PDF
Présentation Oxiane 2016
ODP
Présentation OXiane 2015
PPT
DevoxxFR Présentation des portails en 2014
PPT
Présentation OXiane Value
ODP
Introduction aux méthodes agiles pour conduite de projet
PDF
Usine Logicielle 2013
PPTX
Affichage d'un document Office sous Android
Présentation Oxiane 2016
Présentation OXiane 2015
DevoxxFR Présentation des portails en 2014
Présentation OXiane Value
Introduction aux méthodes agiles pour conduite de projet
Usine Logicielle 2013
Affichage d'un document Office sous Android

Dernier (7)

PPTX
Souveraineté numérique - Définition et enjeux pour les entreprises et les dév...
PDF
Modems expliqués- votre passerelle vers Internet.pdf
PDF
FORMATION EN Programmation En Langage C.pdf
PDF
presentation_with_intro_compressee IEEE EPS France
PDF
Tendances tech 2025 - SFEIR & WENVISION.pdf
PPTX
Presentation_Securite_Reseaux_Bac+2.pptx
PDF
FORMATION COMPLETE EN EXCEL DONE BY MR. NYONGA BRICE.pdf
Souveraineté numérique - Définition et enjeux pour les entreprises et les dév...
Modems expliqués- votre passerelle vers Internet.pdf
FORMATION EN Programmation En Langage C.pdf
presentation_with_intro_compressee IEEE EPS France
Tendances tech 2025 - SFEIR & WENVISION.pdf
Presentation_Securite_Reseaux_Bac+2.pptx
FORMATION COMPLETE EN EXCEL DONE BY MR. NYONGA BRICE.pdf

Google Web Toolkit 1.5 Presentation Web Creative Common

  • 1. Google Web Toolkit 1.5 JW-GWT
  • 2. Ce qui précède n'affecte en rien vos droits en tant qu'utilisateur (exceptions au droit d'auteur : copies réservées à l'usage privé du copiste, courtes citations, parodie...) Ceci est le Résumé Explicatif du Code Juridique (la version intégrale du contrat) .
  • 4. Google Web Toolkit – Plan Général (1) Introduction Les technologies du Web 2.0 Les principes d’Ajax Les applications RIA L’approche de GWT Développer une appli GWT Installation Créer et tester une application Les fenêtres et les panels Les composants graphiques Gestion de l’internationalisation Les feuilles de styles CSS Le modèle événementiel
  • 5. Google Web Toolkit – Plan Général (2) Communications asynchrones Présentation de GWT RPC Impact des comm. asynchrones Implémenter un service Sérialisation Gestion des exceptions Utilisation de JSON Gestion de l'historique Notions avancées Utilisation d’images Intégration Java EE Tester avec Junit Présentation de JSNI
  • 7. Naissance des RIA (1) L'histoire du développement d'applications a connu plusieurs grandes phases Les terminaux passifs (années 70) La révolution du client-serveur (années 80) La révolution internet et intranet (années 90) L'évolution vers les 'clients riches' (années 2000) RIA = Rich Internet Application. RDA = Rich Desktop Application GWT
  • 8. Naissance des RIA (2) Les terminaux passifs Terminaux connectés à un mainframe (3270), interface en mode texte, tout est géré par le serveur La révolution du client-serveur L'équipement des utilisateurs en postes de travail (PC) a permis le développement de la bureautique dans un premier temps puis celui du client-serveur Client serveur 1ère génération : toute la logique sur le client, communication avec un serveur de données (bases de données, mainframes…), souvent nommé 'Client lourd' Client serveur 2ème génération : gestion de l'interface graphique sur le poste client et interaction avec une partie applicative exécutée côté serveur (CORBA, DCOM, …)
  • 9. Naissance des RIA (3) La révolution internet et intranet A partir de 1995, internet se développe et les utilisateurs se familiarisent avec l'utilisation d'un navigateur En parallèle, les équipes de développement sont confrontées aux limites du client-serveur (essentiellement le problème de déploiement et de gestion des mises à jour) L'infrastructure technique d'internet (HTTP, HTML, navigateur) va progressivement se généraliser en entreprise. Les applications intranet sont, au début, surtout réservées pour de la consultation. Au fil des ans, elles vont devenir de plus en plus sophistiquées Pour les utilisateurs et les exploitants l'architecture Web est un progrès majeur. Pour les développeurs, le passage est plus délicat : le couple HTTP/HTML n'a pas été conçu pour faire des applications. Principales technologies pour le développement d'applications Intranet : Java EE, PHP, .NET
  • 10. Naissance des RIA (4) L'évolution vers les 'clients riches' Les demandes d'applications intranet de plus en plus sophistiquées se sont heurtées aux limites graphiques du HTML Manque d'interactivité, composants graphiques basiques, nécessité de faire des allers-retours pour une simple information à rafraîchir… Plusieurs solutions ont émergé, regroupées sous le terme 'clients riches'. Leur but : combiner la richesse ergonomique du client-serveur avec la souplesse de l'architecture Web RIA (Rich Internet Application) : le navigateur web reste le socle côté client. Les possibilités du navigateur sont soit exploitées au maximum (Javascript et CSS) soit enrichies par l'ajout de plugins (Flash, Silverlight, JavaFX, …) RDA (Rich Desktop Application) : renaissance du client-serveur 2ème génération, prévoit des solutions pour le problème d'installation et de mise à jour (ex: Eclipse RCP)
  • 11. RIA, Web 2.0 et Ajax Le terme Web 2.0 résume l'évolution vers plus de richesse des sites internet Désigne surtout des aspects non techniques (les sites deviennent plus collaboratifs, participatifs, …) Techniquement utilisation importante de JavaScript JavaScript Créé en 1995 par Netscape. Permet d'intégrer, dans les pages HTML, des scripts interprétés par le navigateur D'abord utilisé pour limiter les échanges avec le serveur en assurant des contrôles de saisie côté client Progressivement deux utilisations majeures se sont démocratisées : Ajax et DHTML
  • 12. Ajax En 2005, le terme Ajax est apparu mettant un nom sur une pratique de plus en plus courante Ajax = Asynchronous JavaScript and XML Du code JavaScript émet des requêtes HTTP pour échanger des flux XML avec la partie serveur (objet XMLHttpRequest) Ce code peut s'exécuter indépendamment des actions de l'utilisateur Permet, par exemple, le rafraîchissement d'une partie de la page ou encore le remplissage progressif d'un arbre ou d'une table Rend les applications plus interactives en évitant les rafraîchissements complets des pages Réduit les flux échangés avec le serveur en se limitant aux données nécessaires
  • 13. DHTML Après avoir téléchargé un fichier HTML, le navigateur créé en mémoire un arbre représentant la structure de la page puis l'affiche Le DOM : Document Objet Model Le contenu du DOM peut être manipulé dynamiquement en utilisant JavaScript Ajout et suppression de nœuds Modification d'attributs (emplacement, style, …) La mise au point du JavaScript est délicate Différences de fonctionnement entre les navigateurs. Environnements de développement sommaires Des frameworks JavaScript ont émergés : jQuery, prototypeJS, Scriptaculous…
  • 14. L’approche de GWT Mai 2006 : annonce de GWT à la conférence JavaOne Google Web Toolkit Ecrire ses applications clientes en Java Les compiler en Javascript Javascript = le bytecode du web Compris par tous les navigateurs Bas niveau, puissant
  • 15. Avantages de l'approche GWT Développer et maintenir des applis Javascript Supportant les spécificités des navigateurs Gère automatiquement Internet Explorer, FireFox, Mozilla, Safari, Opéra Gère automatiquement les différences entre les versions des navigateurs Supportant l'internationalisation Supportant des alternatives de configuration (intranet/extranet) De plus en plus complexes Java est conçu pour gérer des développements complexes Optimales Produit des versions spécifiques plutôt que génériques des fichiers Utiliser la myriade d'outils du monde Java IDE, conception, analyse de code, test, intégration continue, … Ne pas redévelopper tout ça une nouvelle fois
  • 16. Principes généraux (1) Mise à disposition de librairies de classe Java Classes graphiques (widgets, panels) Permettent de composer une application type &quot;client desktop&quot; comme du Swing Classes de communication avec le serveur Permettent d'échanger des informations structurées (XML, JSON, …) Permettent même d'échanger directement des objets Java Permettent d'intégrer coté client des services écrits dans différents langages Compilateur de Java vers Javascript Supporte une version simplifiée du JRE Possibilité d'intégrer des frameworks Javascript Scriptaculous, JSCalendar, TinyMCE, MooTools, Ext-JS… Intégration possible avec les frameworks j2ee JSF, Spring, Struts, EJB, …
  • 17. Principes généraux (2) Développement des applications reste difficile Tests unitaires avec JUnit Navigateur interne pour la mise au point (mode &quot;hosted&quot;) Pas de déploiement préalable Le code qui s'exécute est du code Java Debug en Java, points d'arrêt, … Compiler en JavaScript ensuite Déployer et tester (mode &quot;web&quot;)
  • 18. Schéma général Compilateur Java->Javascript JRE Emulation JSNI JavaScript Native Interface Widgets &Panels I18n RPC Gestion de l'historique (bouton &quot;Back&quot;) XML Parser Intégration JUnit
  • 19. Compilation Java Transformation du code source Java Décrivant des classes, des méthodes Respectant la syntaxe Vers du bytecode Code binaire 'interprétable' par une machine virtuelle (JVM) Des instructions machines mais pour une machine virtuelle JVM = fonctions de base (natives) + gestion mémoire Résolution des références avec le ClassPath Contient notamment le JRE (les classes de base du système) En particulier le noyau (java.lang)
  • 20. Compilation GWT Java vers JavaScript Exécuter la classe com.google.gwt.dev.GWTCompiler Avec une définition de &quot;module&quot; et un fichier de configuration Module = ensemble de fichiers liés (Java et autres) Configuration indique typiquement un point d'entrée : la classe principale Le compilateur part de ce point d'entrée Et suit les dépendances Ne compile que ce qui est utilisé Minimiser la taille des fichiers générés Utiliser des grosses bibliothèques sans risquer de surcharger le runtime final Produit des fichiers JavaScript Spécifiques pour chaque navigateur et pour chaque locale Attention : n'utilise que les fichiers Java (pas les .class) Nécessité de disposer des sources de toutes ses librairies utilisées
  • 21. Modes de compilation Mode &quot;OBFUSCATE&quot; Nom de classes, d'attributs, de méthodes, … sont compressés Illisible mais compact (protège aussi son code) Mode &quot;PRETTY&quot; Noms courts On reconnaît au moins le nom des méthodes Mode &quot;DETAILED&quot; Noms complets Permet de refaire le lien avec le code Java en cas de bug
  • 22. Fichiers générés (&quot;permutation&quot;) Autant de fichiers que de combinaisons Type de navigateur Locale Propriété de configuration (typiquement internet/intranet) Les fichiers ne sont pas génériques Ne contiennent pas des &quot;if&quot; pour gérer les spécificités Un fichier de sortie = une &quot;permutation&quot; Le navigateur ne reçoit pas de code inutile Diminue l'utilisation de la bande passante Diminue l'empreinte mémoire dans le navigateur
  • 23. Intégration JSNI Méthodes natives En Java : méthodes dont le code existera dans la jvm JavaScript Native Interface Spécifier des méthodes &quot;natives&quot;, dont le code existera au runtime Intégrer le code JavaScript directement dans le code Java On met le code en commentaire derrière la définition Ça reste du code Java valide puisque dans des commentaires Le compilateur insère ce code dans le fichier généré Permet D'optimiser De gérer des spécifités, d'intégrer des librairies existantes public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
  • 24. JRE Emulation Reprend un sous ensemble des classes de base Java Fournit un équivalent JavaScript de ces classes Packages java.lang, java.util, java.lang.annotation Assez complet mais pas toutes les méthodes Package java.io OutputStream, PrintStream, Serializable Package java.sql Date, Time, Timestamp
  • 25. Limitations Syntaxe Java 5 (enum, types génériques, …) Supportée depuis GWT 1.5 La librairie du JRE est volontairement limitée Certaines subtilités Float/Double ne peuvent pas servir de clé dans une HashMap String.replaceAll, replaceFirst, split : regexp de JavaScript StringBuffer(int) et StringBuffer se comportent pareils System.out et err existent mais ne servent pas en mode web Pas de support des stack-trace dans les Throwable Vector : pas de capacité, de grossissement, de vérification d'indices Laisse entrevoir les types de problèmes à prévoir Mais pas si gênant que ça, il suffit de créer/utiliser d'autres librairies
  • 26. Comparaisons Swing Logique similaire mais pas de MVC (pas de modèle), pas de Layout Echo2 Logique similaire mais tourne côté serveur Beaucoup plus d'appels vers le serveur et nécessité d'un serveur J2EE JSF Compliqué, tourne côté serveur, pas vraiment du client riche On peut intégrer du GWT dans des applis JSF et autres &quot;struts like&quot; Ruby on Rail Plutôt côté serveur avec automatismes ajax générés sur le client Pas aussi interactif (GWT est plus orienté client)
  • 28. Installation Vérifier la présence d'un JRE Version 1.5 supportée depuis GWT 1.5 Téléchargement sur le site officiel http://code.google.com/intl/fr/webtoolkit/download.html Fichier compressé (gwt-windows-1.5.3.zip pour Windows) Décompresser : c'est prêt On utilisera aussi un IDE Outillage offre des facilités pour eclipse Mais tout autre IDE convient aussi
  • 29. Installation : arborescence obtenue C:\GWT │ about.html │ about.txt │ applicationCreator.cmd script de création d'application │ benchmarkViewer.cmd │ COPYING │ COPYING.html │ gwt-benchmark-viewer.jar │ gwt-dev-windows.jar │ gwt-ll.dll │ gwt-module.dtd │ gwt-servlet.jar │ gwt-user.jar │ i18nCreator.cmd script d'internationalisation │ index.html point d'entrée html (doc et exemples) │ junitCreator.cmd script de création tests junit │ projectCreator.cmd script de création de projet (eclipse) │ release_notes.html │ swt-win32-3235.dll │ ├─── doc répertoire de documentation ... └─── samples répertoires d'exemples
  • 30. Créer et tester une application Script &quot;applicationCreator&quot; Fait partie des fichiers installés Pour créer une application simple (type &quot;Hello World&quot;) Permet de créer l'arborescence et les fichiers de base Package doit se terminer par le sous package &quot;.client&quot; Propose des options (qu'on verra plus tard) applicationCreator -out dir className
  • 31. Créer et tester une application : création Création d'une application simple App Fichiers produits applicationCreator -out TP1 com.oxiane.formation.tp1.client.App C:\GWT\TP1 │ App-compile.cmd script compilation JavaScript │ App-shell.cmd script exécution mode hosted │ └─── src répertoire source └─── com └─── oxiane └─── formation └─── tp1 package de l'application │ App.gwt.xml description du module GWT │ ├─── client package client (code du client) │ App.java classe &quot;point d'entrée&quot; │ └─── public package public (fichiers web) App.css Feuille de style css de l'appli App.html Fichier html de chargement web
  • 32. Tester l'application : mode &quot;hosted&quot; Utiliser le script &quot;App-shell&quot; généré Ouvre un &quot;GWT Development Shell&quot; Sert de console (trace) Ouvre un &quot;Hosted Browser&quot; Internet Explorer sous Windows Mozilla sur les autres OS Exécution en Java Exceptions capturées Debug Java possible Moteur tomcat embarqué Moteur de servlet Déploiement automatique du code serveur
  • 33. Fichiers ajoutés par le mode &quot;Hosted&quot; Mode &quot;Hosted&quot; ajoute une arborescence tomcat Tomcat embarqué dans le GWT Shell Development C:\GWT\TP1 … code de l'application inchangé └─── tomcat arborescence simplifiée tomcat ├─── conf │ │ web.xml │ │ │ └─── gwt │ └─── localhost ├─── webapps │ └─── ROOT │ └─── WEB-INF │ web.xml conf de l'application web │ └─── work répertoire de travail tomcat └─── gwt └─── localhost └─── _ tldCache.ser cache des taglib descriptors
  • 34. Tester l'application : mode &quot;Web&quot; Utiliser le script &quot;App-compile&quot; généré Ou utiliser le bouton Compile/Browse du &quot;Hosted Browser&quot;
  • 35. Fichiers ajoutés par le mode &quot;Web&quot; Mode &quot;Web&quot; utilise la version compilée JavaScript C:\GWT\TP1 ... répertoires inchangés └─── www répertoire ajouté ├─── .gwt-tmp tmp de compilation │ └─── compiler │ └─── com.oxiane.formation.tp1.App … └─── com.oxiane.formation.tp1.App répertoire de l'appli … │ App.css │ App.html … │ com.oxiane.formation.tp1.App.nocache.js appli JavaScript … └─── gwt fichiers gwt TP 1
  • 36. Utilisation dans un IDE Développement GWT = Développement Java pur N'importe quel IDE convient si on respecte l'arborescence Outillage spécifique pour eclipse Scripts proposent l'option &quot;-eclipse&quot; Gère les fichiers spécifiques tels que &quot;.project&quot; et &quot;.classpath&quot; &quot;.launch&quot; pour lancer les scripts avec les menus &quot;Run as&quot; Projet directement importable dans eclipse Ou IDE capable d'importer des projets eclipse (Netbeans,…) Utiliser le script &quot;projectCreator&quot; en premier Création de la structure de projet Ne pas oublier l'option &quot;-eclipse nomProjet&quot; avec les autres scripts
  • 37. Cycle de développement Scripts = cycle de dév Ne pas oublier &quot;-eclipse&quot; Internationalisation Préparation du projet Fichier de propriétés JUnit Préparation du projet Classe de test prête à remplir projectCreator Eclipse ? applicationCreator I18n ? i18nCreator JUnit ? junitCreator Import du projet Fin Début Eclipse ? O N O O O N N N
  • 38. Script &quot;projectCreator&quot; Création de la structure de projet Remarques Utiliser au moins &quot;-ant&quot; ou &quot;-eclipse&quot; (les deux sont possibles) projectCreator [-ant nomProjet] Générer un script Ant de compilation des sources (extension &quot;.ant.xml&quot; ajoutée) [-eclipse nomProjet] Création pour un projet eclipse [-out répertoire] Répertoire de génération (&quot;.&quot; par défaut) [-overwrite] Ecraser les fichiers existants (alerte sinon) [-ignore] Ignorer les fichiers existants (ne pas écraser) [-addToClassPath entrée] Ajouter une entrée au classPath
  • 39. Script &quot;applicationCreator&quot; Création de l'application par défaut Remarques Classe doit être dans un sous-package &quot;client&quot; (alerte sinon) En mode eclipse Génération de &quot;.launch&quot; pour lancer les scripts Mise à jour des fichiers spécifiques eclipse (.classpath, .project, …) applicationCreator [-eclipse nomProjet] Création pour un projet eclipse [-out dir] Répertoire de génération (&quot;.&quot; par défaut) [-overwrite] Ecraser les fichiers existants (alerte sinon) [-ignore] Ignorer les fichiers existants (ne pas écraser) [-addToClassPath entrée] Ajouter une entrée au classPath [-addModule module] Ajouter un module GWT dans l'héritage nomCompletClasse Nom complet de la classe à créer
  • 40. Script &quot;i18nCreator&quot; Création du support de l'internationalisation On étudiera cela en détail plus tard Le principe général est d'utiliser une interface dans le code Propose une méthode pour chaque &quot;constante&quot; à internationaliser Implémentation automatique à partir de fichiers de propriétés i18nCreator [-eclipse nomProjet] Création pour un projet eclipse [-out répertoire] Répertoire de génération (&quot;.&quot; par défaut) [-createConstantsWithLookup] ConstantsWithLookup plutôt que Constants [-createMessages] Messages plutôt que Constants [-overwrite] Ecraser les fichiers existants (alerte sinon) [-ignore] Ignorer les fichiers existants (ne pas écraser) nomCompletInterface Nom complet de l'interface à créer
  • 41. Script &quot;junitCreator&quot; Création du support de JUnit On étudiera cela en détail plus tard Le principe général est de préparer le projet à l'utilisation de JUnit Création des répertoires Création d'une classe pour écrire ses tests En mode eclipse, création d'un &quot;.launch&quot; pour lancer l'exécution des tests junitCreator -junit cheminJUnit Chemin vers le jar de junit -module nomModule Nom du module GWT à utiliser [-eclipse nomProjet] Création pour un projet eclipse [-out répertoire] Répertoire de génération (&quot;.&quot; par défaut) [-overwrite] Ecraser les fichiers existants (alerte sinon) [-ignore] Ignorer les fichiers existants (ne pas écraser) [-addToClassPath entrée] Ajouter une entrée au classPath
  • 42. Import dans eclipse Import de projet existant Recopier les fichiers dans le workspace Ou bien générer directement dans le répertoire du workspace
  • 43. Autres alternatives de création de projet Ecrire les fichiers à la main Pas très réaliste Disposer d'un assistant de création dans l'IDE Plugin eclipse GWT, support natif de GWT dans IntelliJ, … Existent mais n'apportent pas énormément GWT évolue encore, mieux vaut utiliser les outils fournis Recopier/générer l'arborescence de fichiers Permettrait de préparer un squelette institutionnel d'application Dans tous les cas, même structure finale TP 2
  • 44. Cypal Studio (1) Plugin eclipse pour simplifier l'utilisation de GWT Site http://code.google.com/p/cypal-studio/ Assistants Création de modules : remplace projectCreator et applicationCreator Création de services (concerne la communication serveur) Lanceur en mode Hosted Problèmes Projet peu actif Ne couvre pas les possibilités des outils GWT tels que junitCreator Intéressant mais pas fondamental
  • 45. Cypal Studio (2) Installation Pré-requis : Eclipse IDE for Java EE Developers (Eclipse + WTP) Dézipper dans le répertoire 'dropins' d'Eclipse et relancer Eclipse Configuration Indiquer l'emplacement de GWT dans les préférences
  • 46. Cypal Studio (3) Création d'un projet Cypal fonctionne pour les projets de type 'Dynamic Web Project' Module Version 2.4 obligatoire (version de la spec servlet) Choisir la configuration 'Cypal Studio for GWT'
  • 47. Cypal Studio (4) Création d'un module GWT A partir de menu 'File->New…' lancer l'assistant de création de module GWT
  • 48. Cypal Studio (5) Pour tester Ouvrir le gestionnaire des configurations de lancement Créer une configuration de lancement 'GWT Hosted Mode Application' Sélectionner le projet associé et le module GWT à lancer
  • 50. Interface EntryPoint L'interface désignant un point d'entrée d'application Méthode onModuleLoad() Equivalent au main() de l'application ou au service() des Servlets Coder une classe implémentant cette interface La désigner dans le fichier de description de module <entry-point class='com.oxiane.formation.tp1.client.App'/> Le compilateur part de cette classe Et suit les dépendances public class App implements EntryPoint { public void onModuleLoad() { Label label = new Label(&quot;Hello world !&quot;); RootPanel.get().add(label); } }
  • 51. Les fenêtres et les panels Notions classiques des interfaces graphiques Widget = contrôle utilisé par l'utilisateur Exemple : boutons, champs de saisie, etc. Panel = conteneur de widgets (ou d'autres panels) Exemple : table disposant un bouton et un champ en ligne En réalité, un panel peut aussi offrir de l'interactivité Window = la fenêtre du navigateur Accès aux méthodes, propriétés et événements du navigateur Dans la pratique, trois types de composants Widget Panel pour disposer (layout) Panel pour interagir Panel Widget Widget Panel Widget
  • 52. Window Classe encapsulant la fenêtre du navigateur Équivalent de l'objet &quot;window&quot; de JavaScript Méthodes statiques, permettent d'interroger/piloter le navigateur Méthodes et propriétés (getter et/ou setter) diverses Accès aux dimensions utiles, au titre, à la zone de status, au scroll Dialogues simples : alert, confirm, prompt Pilotage : print, open (ouverture d'un autre navigateur) Gère des listeners (WindowClose et WindowResize) Contient une autre classe Window.Location Pour tout ce qui est spécifique à l'url
  • 53. RootPanel Panel racine Associé à un élément de la page Créé par le framework Obtenu par la méthode statique get(String) Paramètre identifie un élément html Permet d'ajouter des widgets sur n'importe quel élément html identifié Panel racine par défaut Méthode get() sans paramètre Utilisé généralement dans le EntryPoint Dans le onLoadModule(), pour ajouter les widgets
  • 54. Les composants graphiques Widget : classe Java En général en correspondance avec un équivalent HTML Button, TextBox, TextArea, CheckBox, RadioButton, … Différentes variations de la table HTMLTable, Grid, FlexTable Des composants plus spécifiques TabPanel : widgets dans différents onglets PopUpPanel StackPanel Plus de 30 widgets et panels en tout Présentés dans le Showcase (exemples de l'aide) TP 3
  • 55. UIObject La racine des objets graphiques Encapsule un élément DOM Propriété &quot;element&quot; Gère un style associé à cet élément Méthodes getStyleName, addStyleName, … (on verra plus tard les styles CSS) Gère un positionnement et des dimensions Propriétés &quot;width, &quot;height&quot;, &quot;size&quot;, &quot;pixelSize&quot;, &quot;absoluteLeft&quot;, &quot;absoluteTop&quot;, … Gère un &quot;title&quot; Attention : texte de bulle d'aide et non un titre Gère la visibilité de l'élément Gère un masque d'événements Méthodes sinkEvents() et unsinkEvents() (on verra plus tard les événements)
  • 56. Début de hiérarchie (UIObject) UIObject MenuItem MenuItemSeparator TreeItem Widget Composite FileUpload FocusWidget Frame Hidden Hyperlink Image Label MenuBar Panel Tree NamedFrame
  • 57. Widget Classe abstraite héritant de UIObject Possède une représentation DOM interne Correspond à la &quot;vision&quot; JavaScript Méthodes positionnant des propriétés Positionne en réalité des attributs de style Exemple : setHeight(&quot;100px&quot;); setPixelSize(100,200); Propriété &quot;title&quot; correspond à la bulle d'aide Préférer l'utilisation des feuilles styles Permet de bien séparer le fonctionnel de la présentation Propose aussi d'autres méthodes Accès au panel conteneur et gestion des événements (plus tard) UIObject Widget
  • 58. MenuBar, MenuItem et Command MenuBar Contient des MenuItem et MenuItemSeparator Horizontal par défaut (booléen pour basculer) MenuItem Libellé + Command ou MenuBar (menus hiérarchiques) Construction simplifiée avec addItem() MenuItemSeparator addSeparator() Command Interface pour représenter une action Méthode execute() invoquée lorsqu'on cliquera sur l'item Généralement implémentée avec une classe interne anonyme UIObject Widget MenuBar
  • 59. Interfaces HasText et HasHTML HasText Identifie un composant contenant un texte Propose les méthodes setText() et getText() Propose en général un constructeur avec String Exemples : MenuItem, Button, Label, Hyperlink, … HasHTML Identifie un composant contenant du texte HTML Hérite de HasText Propose les méthodes setHTML() et getHTML() Propose en général un constructeur avec un String et un booléen &quot;asHTML&quot; Booléen indique si le texte doit être interprété comme texte HTML ou non Exemples : MenuItem, TreeItem, Button, …
  • 60. Interface HasAnimation Marque un widget utilisant une animation Propose de quoi tester et activer l'animation Méthode isAnimationEnabled() Méthode setAnimationEnabled(boolean) Exemple MenuBar, DialogBox, TabPanel, …
  • 61. MenuBar : exemple MenuBar menu = new MenuBar(); MenuBar menuFichier = new MenuBar(true); menuFichier.addSeparator(); Command cmdPlusTard = new Command() { public void execute() { Window.alert(&quot;pas implémentée !&quot;); } }; menuFichier.addItem(&quot;Quitter&quot;, cmdPlusTard); menu.addItem(&quot;Fichier&quot;, menuFichier); MenuBar menuAide = new MenuBar(true); menuAide.addItem(&quot;A propos&quot;, new Command() { public void execute() { ouvrirAPropos(); } }); menu.addItem(&quot;Aide&quot;, menuAide); RootPanel.get().add(menu); TP 4
  • 62. Widget : Image Un widget pour afficher une image Préciser une URL Soit dans le constructeur Soit dynamiquement avec le setter Répertoire &quot;public&quot; de l'application Pour les ressources statiques Notion de &quot;ViewPort&quot; Permet de n'afficher qu'une partie de l'image Préciser le rectangle visible dans le constructeur ou avec le setter Peut réagir à des événements (on verra plus tard) UIObject Widget Image
  • 63. Widget : Frame Un widget pour encapsuler un site Utilise un frame invisible (IFRAME) Préciser l'url (on peut la changer dynamiquement) La sous-classe NamedFrame Ajoute une propriété &quot;nom&quot; Permettra de l'utiliser comme cible d'un FormPanel UIObject Widget Frame NamedFrame
  • 64. Widget : Hidden Un widget pour encapsuler un champ caché Permet de gérer le nom et la valeur du champ UIObject Widget Hidden
  • 65. Widget : Hyperlink Un widget pour spécifier un hyperlien &quot;interne&quot; Un lien vers un &quot;état&quot; de l'application On y reviendra plus tard avec la gestion de l'historique Implémente HasText et HasHTML UIObject Widget Hyperlink
  • 66. Interface HasDirection Indiquer qu'un widget possède son sens de lecture Propose les accesseurs getDirection() et setDirection() Enumeration Direction proposant les constantes LTR : lecture de gauche à droite RTL : lecture de droite à gauche DEFAULT : le sens de lecture naturel (hérité de son parent) Concerne les widgets textuels comme les Label
  • 67. Interface HasWordWrap Marque un widget disposant de la propriété WordWrap Permet d'activer le passage à la ligne sans césure Propose les méthodes getWordWrap() et setWordWrap(boolean) Concerne les widgets textuels Label, HTML, Anchor, …
  • 68. Interface HasAlignment Marque un widget avec alignement horizontal et vertical Hérite de l'interface HasHorizontalAlignment Classe interne HorizontalAlignmentConstant définit les constantes ALIGN_LEFT : alignement à gauche ALIGN_CENTER : alignement centré ALIGN_RIGHT : alignement à droite ALIGN_DEFAULT : alignement &quot;naturel&quot; (gauche si on lit de gauche à droite) Propose les accesseurs de la propriété &quot;horizontalAlignment&quot; Hérite de l'interface HasVerticalAlignment Classe interne VerticalAlignmentConstant définit les constantes ALIGN_BOTTOM : alignement en bas ALIGN_MIDDLE : alignement centré vertical ALIGN_TOP : alignement en haut Propose les accesseurs de la propriété &quot;verticalAlignment&quot;
  • 69. Hiérarchie partielle (Label) UIObject Widget Label HTML InlineLabel InlineHTML
  • 70. Widget : Label Un widget contenant du texte brut Implémente HasText (mais pas HasHTML) HasWordWrap HasDirection HasHorizontalAlignment Une sous classe InlineLabel ? Label utilise un élément <div> InlineLabel utilise un élément <span> produisant un layout en ligne UIObject Widget Label InlineLabel
  • 71. Widget : HTML Un label contenant du texte HTML Hérite des interfaces de Label et ajoute HasHTML Comme pour Label, version &quot;inline&quot; HTML utilise un élément <div> InlineHTML utilise un élément <span> UIObject Widget HTML InlineHTML
  • 72. Widget : Tree Un widget pour représenter une arborescence Implémente HasAnimation, HasFocus Contient des TreeItem Similaire au MenuBar et ses MenuItem TreeItem contient lui même un widget TreeItem : un texte et un &quot;UserObject&quot; Propose Méthodes addItem(TreeItem) et ses variantes avec String et Widget Méthodes remove(), removeItem(), removeItems(), clear() Méthodes iterator() et treeItemsIterator() : parcours des items Méthodes de gestion de la sélection UIObject Widget Tree
  • 73. Widget : FileUpload Encapsule la fonctionnalité du navigateur L'utilisateur choisit un fichier local Fonctionnalité généralement sensible et protégée Seul moyen d’accéder au système de fichier Pas de valeur par défaut sur certains navigateurs Doit être intégré dans un formulaire avec un encoding multi-part Nécessite une partie serveur Pour recevoir le fichier UIObject Widget FileUpload
  • 74. Hiérarchie partielle (FocusWidget) UIObject Widget FocusWidget Anchor ListBox SimpleCheckBox ButtonBase RichTextArea Button SimpleRadioButton TextBoxBase CheckBox CustomButton RadioButton PushButton ToggleButton TextArea TextBox PasswordTextBox
  • 75. Interface HasFocus Marque un widget capable de gérer le focus Hérite de SourcesFocusEvent et SourcesKeyboardEvent Capable d'avoir des FocusListener et des KeyboardListener On verra plus tard la gestion des événements Propose de quoi gérer le focus et le tabIndex Méthode getTabIndex() : position dans la chaîne de tabulation Méthode setTabIndex(int index) : définir cette position Valeur -1 pour enlever le widget de la chaine Méthode setFocus(boolean) : prendre/laisser le focus Un seul widget peut avoir le focus, il prend alors tous les événements clavier Méthode setAccessKey(char) : raccourcis pour prendre le focus Combiner avec une touche spéciale (exemple Alt) pour prendre le focus
  • 76. Widget : FocusWidget Racine des widgets capables de gérer le focus D'autres widgets implémentent aussi HasFocus Les widgets dans lesquels on peut saisir Les widgets manipulables au clavier Apporte aussi la notion &quot;enabled&quot; Propose les accesseurs isEnabled() et setEnabled() UIObject Widget FocusWidget
  • 77. Interface HasName Marque un widget disposant d'un nom Propose les méthodes getName() et setName(String) Permet de l'utiliser dans un FormPanel Nom associé au widget quand le formulaire est soumis
  • 78. Widget : Anchor Un widget représentant un ancrage Encapsule un élément <a> Implémente HasText HasHTML HasHorizontalAlignment HasWordWrap HasDirection HasName UIObject Widget FocusWidget Anchor
  • 79. Widget : ButtonBase et Button Racine des widgets de type Bouton Traditionnellement les Button, CheckBox et RadioButton Implémente HasHTML Button Un bouton d'action On lui associe un ClickListener pour réagir au clic Méthode click() pour simuler programmatiquement le clic UIObject Widget FocusWidget ButtonBase Button
  • 80. Widget : CheckBox, SimpleCheckBox Widget représentant une case à cocher Introduit une propriété &quot;checked&quot; Propose les accesseurs isChecked() et setChecked() Implémente HasName (utilisable dans un formulaire) CheckBox affiche son label Passé dans le constructeur SimpleCheckBox n'a pas de label UIObject Widget FocusWidget ButtonBase CheckBox SimpleCheckBox
  • 81. Widget : RadioButton, SimpleRadioButton Des boutons exclusifs Doivent appartenir à un même &quot;groupe&quot; Le &quot;name&quot; hérité sert à définir le groupe L'indiquer dans le constructeur RadioButton affiche son label SimpleRadioButton n'as pas de label UIObject Widget FocusWidget ButtonBase CheckBox SimpleCheckBox RadioButton SimpleRadioButton
  • 82. Widget : CustomButton Racine des boutons personnalisables Associer des images ou des textes Selon que le bouton est enfoncé ou non UIObject Widget FocusWidget ButtonBase CustomButton
  • 83. Widget : PushButton Un bouton d'action personnalisable Permet de lui associer des images Permet de gérer le déroulement d'un clic Méthode onClickStart() : début du clic Méthode onClickCancel() : clic annulé Méthode onClick() : clic de l'utilisateur UIObject Widget FocusWidget ButtonBase CustomButton PushButton
  • 84. Widget : ToggleButton Un CheckBox personnalisable Spécifier des images, le bouton peut rester enfoncé Méthodes pour gérer la sélection Méthode isDown() Méthode setDown() Méthode onClick() UIObject Widget FocusWidget ButtonBase CustomButton ToggleButton
  • 85. Widget : TextBoxBase Racine des widgets de saisie textuelle Implémente HasText, HasName et HasFocus Introduit les propriétés &quot;readOnly&quot; : lecture seule &quot;cursorPos&quot; : position du curseur &quot;textAlignment&quot; : alignement du text Constantes ALIGN_[LEFT, CENTER, RIGHT, JUSTIFY] Accès au text sélectionné getSelectedText(), getSelectedLength(), selectAll(), setSelectionRange() Filtrage de la saisie setKey(char) : réception d'un caractère cancelKey() : refuser le caractère en cours de saisie UIObject Widget FocusWidget TextBoxBase
  • 86. Widget : TextBox, PasswordTextBox Le champ de saisie standard Une seule ligne Implémente HasDirection en plus Introduit les propriétés &quot;maxLength&quot; : nombre maxi de caractères &quot;visibleLength&quot; : nombre visible de caractères PasswordTextBox Masque la saisie UIObject Widget FocusWidget TextBoxBase TextBox
  • 87. Widget : TextArea Une zone de texte multi-lignes Implémente HasDirection en plus Introduit les propriétés &quot;visibleLines&quot; : nombre de lignes visibles &quot;characterWidth&quot; : longueur des lignes UIObject Widget FocusWidget TextBoxBase TextArea
  • 88. Widget : RichTextArea Saisie de texte riche (HTML) Style et formatage Implémente HasText, HasHTML et HasFocus getText() : le texte brut sans formatage getHTML() : le texte HTML Intéressant de lui adjoindre une barre d'outil RichTextToolBar dans le Showcase (pas inclus de base) Copier la classe et les ressources du répertoire Répertoire com.google.gwt.sample.showcase.client.content.text UIObject Widget FocusWidget RichTextArea
  • 89. Widget : ListBox (1) Liste de choix Items sont des String, gérés par leur indice Ajout des items avec addItem(String) Implémente HasName et HasFocus Propriété &quot;selectedIndex&quot; : indice sélectionné &quot;visibleItemCount&quot; : nombre de lignes &quot;multipleSelect&quot; : sélection multiple Méthode insertItem et removeItem (par indice) Méthode getItemCount() : nombre d'items Drop-down (combo) avec setVisibleItemCount(1) UIObject Widget FocusWidget ListBox
  • 90. Widget : ListBox (2) Possibilité de distinguer item et sa valeur Méthode addItem(String item, String valeur) Méthode insert(String item, String value, int index) Accès getItemText(int) et getValue(int) Modification setItemText(int, String) et setValue(int, String) Insertion à l'indice, en fin si négatif ou trop grand Sélection multiple Obligation de parcours Méthode isItemSelected(int) Méthode setItemSelected(int, boolean) Différent de setSelectedItem(int) : sélection simple TP 5
  • 91. La notion de layout Logique différente de Swing Difficile de mapper vers des éléments HTLM => approche différente GWT propose un ensemble de Panel Affichent de manière spécifique leurs widgets Exemples HorizontalPanel : widgets de gauche à droite FlowPanel : comme HTML, de gauche à droite mais passe à la ligne AbsolutePanel : positionnement absolu
  • 92. Panel, Composite et HasWidgets Pattern &quot;composite&quot; classique dans les GUI Certains widgets contiennent d'autres widgets Permet d'assembler de manière récursive les interfaces Remarque : ce sont eux-mêmes des widgets (récursivité) Panel Classe naturelle pour effectuer un &quot;regroupement&quot; (plutôt layout) Composite Plutôt un widget complexe contenant déjà des widgets Propose de l'intéraction, ce que ne fait généralement pas le panel Interface HasWidgets Une interface pour marquer les widgets conteneurs
  • 93. Interface HasWidgets Marque un widget qui peut contenir des widgets Hérite de Iterable qui propose la méthode iterator() Typiquement les Panel et les Composite Propose de quoi énumérer les widgets contenus Méthode add(Widget) Méthode remove(Widget) Méthode clear() : supprime tous les widgets Méthode iterator() : retourne un Iterator<Widget> sur les widgets Panel et Composite l'implémentent
  • 94. Hiérarchie partielle (Panel) UIObject Widget Panel ComplexPanel HorizontalSplitPanel AbsolutePanel HTMLTable SimplePanel VerticalSplitPanel CellPanel DeckPanel FlowPanel HTMLPanel StackPanel RootPanel DockPanel HorizontalPanel VerticalPanel DecoratedStackPanel DecoratorPanel FocusPanel FormPanel PopupPanel ScrollPanel DecoratedPopupPanel DialogBox
  • 95. Panel Racine des conteneurs de widgets Plutôt destiné au layout Implémente HasWidgets La hiérarchie de composition est accessible Tout widget connaît son conteneur parent En haut de la hiérarchie se trouve le RootPanel Nécessité de garantir l'intégrité de cette composition Gérée dans les méthodes add, remove et setWidget Nécessité de gérer l'attachement et le détachement UIObject Widget Panel
  • 96. Panel : attachement et détachement (1) Fuite mémoire en JavaScript : problème classique Garbage Collector ne peut ramasser les références cycliques En particulier les gestionnaires d'événements (qu'on verra plus tard) Importance de nettoyer ces références cycliques (tâche rébarbative) GWT gère en proposant des méthodes à éventuellement redéfinir Widget conteneur Widget contenu setWidget (ou add) adopt ->setParent() onAttach() //positionne les listeners doAttachChildren() //propager à ses widgets onLoad() setWidget(avec null ou remove) orphan ->setParent(null) onDetach() onUnload doDetachChildren() //propager à ses widgets //retire les listeners
  • 97. Panel : attachement et détachement (2) Respecter quelques règles Appeler super.onAttach() si on redéfinit cette méthode Redéfinir doAttachChildren() si on implémente HasWidgets Ainsi que doDetachChildren() Plutôt redéfinir onLoad() et onOnload()
  • 98. SimplePanel, ComplexPanel Contenir un seul ou plusieurs widgets SimplePanel Un seul widget : accesseurs get et setWidget() Ajout visuel autour du widget DecoratorPanel Ou regroupement de fonctionnement PopupPanel, FormPanel, ScrollPanel, … Ce widget contenu peut bien sûr être un Panel ComplexPanel Plusieurs widgets Permet le layout DeckPanel, FlowPanel, StackPanel, … UIObject Widget Panel SimplePanel UIObject Widget Panel ComplexPanel
  • 99. Interface IndexedPanel Marque un panel aux widgets accessibles pas indice Implique un ordre explicite des widgets contenus Propose Méthode getWidgetCount() : nombre de widgets Méthode getWidget(int) : widget par son indice Méthode getWidgetIndex(Widget) : indice du widget Méthode remove(int) : enlever un widget Concerne la plupart des ComplexPanel
  • 100. FlowPanel Organise ses widgets en lignes C'est le layout naturel de HTML Plusieurs lignes si pas assez large Implémente HasIndexedPanel Propose Méthode addWidget(Widget) Méthode insertWidget(Widget, index) UIObject Widget Panel ComplexPanel FlowPanel
  • 101. CellPanel Dispose ses widgets dans une table Un widget par cellule Implémente HasIndexedPanel C'est une classe abstraite Propriétés &quot;spacing&quot; : espace entre les cellules &quot;borderWidth&quot; : épaisseur de bordure Dimension de cellule Méthodes setCellWidth(), setCellHeight() Alignement de cellule setCellHorizontalAlignment(), setCellVerticalAlignment() UIObject Widget Panel ComplexPanel CellPanel
  • 102. HorizontalPanel, VerticalPanel Dispose ses widgets horizontalement Pas de retour à la ligne (différent de FlowPanel) Implémente IndexedPanel, HasAlignment Autorise aussi l'insertion Méthode insert(Widget, int) VerticalPanel dispose verticalement Sur une seule colonne UIObject Widget Panel ComplexPanel CellPanel HorizontalPanel
  • 103. DockPanel Organise ses widgets dans des zones NORTH, SOUTH, EAST, WEST, CENTER Correspond au BorderLayout de Swing Implémente HasAlignment Méthode add(Widget, DockPanel.Direction) Chaque zone peut contenir plusieurs widgets On peut ajouter plusieurs widgets dans une zone NORTH et SOUTH subsidiaires s'empilent au milieu Deux autres constantes LINE_START et Line_END Gérer le sens de lecture plutôt que EAST-WEST UIObject Widget Panel ComplexPanel CellPanel DockPanel
  • 105. DeckPanel Organise ses widgets en un tas Comme un tas de carte Un seul visible à la fois : showWidget(int) Ne pas confondre avec le DockPanel Implémente HasAnimation et HasIndexed C'est le panel interne utilisé par le TabPanel (onglet) Attention : impacte les dimensions de ses widgets Propose Méthode getVisibleWidget() : indice du widget montré Méthode showWidget(int) : montrer le widget indiqué Méthode insert(Widget, int) : insertion UIObject Widget Panel ComplexPanel DeckPanel
  • 106. StackPanel Organise ses widgets en une pile verticale Un seul montré à la fois : showStack(int) Les autres représentés par un header sensible au click Implémente IndexedPanel Propose Méthode getSelectedIndex() : sélection Méthode showStack(int) : sélectionner Gestion des headers Méthodes addWidget(Widget, String) Méthode setStackText(int, String) Gestion des headers HTML Méthodes addWidget(Widget, String, boolean) Méthode setStackText(int, String, boolean) UIObject Widget Panel ComplexPanel StackPanel
  • 107. DecoratedStackPanel Ajoute simplement une décoration Gestion de coins arrondis à l'aide d'images UIObject Widget Panel ComplexPanel StackPanel Decorated StackPanel
  • 108. AbsolutePanel Positionnement absolu de ses widgets Widgets peuvent se chevaucher Implémente IndexedPanel Positionnement left et top Widgets gardent leurs dimensions Propose Méthode add(Widget, int, int) : ajouter en positionnant Méthode setWidgetPosition(Widget, int, int) Méthodes getWidgetLeft(Widget), getWidgetTop(Widget) Méthode addWidget(Widget) : ajouter en empilant verticalement RootPanel en hérite !!! UIObject Widget Panel ComplexPanel AbsolutePanel RootPanel
  • 109. HTMLPanel Approche complètement différente Encapsuler du code HTML Attacher les widgets aux éléments identifiés de ce code Le layout est géré ailleurs (dans le code HTML) Implémente IndexedPanel Propose Constructeur acceptant le code HTML Méthode add(Widget, String) : ajoute le widget à l'élément identifié Méthode addAndReplaceElement(Widget, id) : ajoute et remplace Méthode createUniqueId() : helper pour créer des id uniques UIObject Widget Panel ComplexPanel HTMLPanel
  • 110. HTMLTable Panel à base de cellules en colonnes Ne pas confondre avec HTMLPanel Widgets dans les cellules, coordonnées row, column Propose Propriété borderWidth : épaisseur de bordure Propriété cellPadding et cellSpacing : espace entre les cellules Méthodes d'accès général Méthodes clear(), clearCell(int, int) et remove(Widget) Méthodes getRowCount(), getCellCount(int), isCellPresent(int, int) Méthodes getWidget(int, int) : version avec Text et HTML Méthodes setWidget(int, int, Widget) : idem Méthodes d'accès aux formatters getColumnFormatter(), getRowFormatter(), getCellFormatter() UIObject Widget Panel HTMLTable
  • 111. Grid Une table avec des dimensions prédéfinies Constructeur Grid(int numRow, int numColumn) Possibilité de redimensionner après coup : resize() Dimensions des rangées et colonnes Pas imposées et variables Largeur de colonne imposée par son widget le plus grand Hauteur de ligne imposée par son widget le plus large Idéal pour organiser dans une structure tabulaire UIObject Widget Panel HTMLTable Grid
  • 112. FlexTable Une table flexible Permet de créer des cellules à la demande Un widget peut s'étaler sur plusieurs cellules Organisation logique en rangées de taille variable Propose Méthodes insertRow(int), removeRow(int) Méthodes getRowCount() et getCellCount(int) : cellules d'une row Méthodes insertCell, insertCells : insertion de cellules dans une row Accès au formateur avec getFlexCellFormatter() Permet de fusionner des cellules UIObject Widget Panel HTMLTable FlexTable
  • 113. DecoratorPanel Ajouter une décoration autour d'un widget En général, le widget contenu est un panel La bordure est constituée d'images Neuf zones : les bords, les coins et le centre Permet de faire des coins arrondis Permet de redimensionner sans détruire le look Définies dans les styles (on verra plus tard) UIObject Widget Panel SimplePanel DecoratorPanel
  • 114. PopupPanel Un panel qui &quot;surgit&quot; au dessus des autres Typiquement tooltip, menu, dialog Ne pas les ajouter à un panel : show() et hide() Dimensions déterminées par son widget contenu Méthodes setWidth() et setHeight() redirigées sur ce contenu Implémente HasAnimation Propriétés &quot;autoHide&quot; : se ferme tout seul (sur clic en dehors) &quot;modal&quot; : capture tous les événements des autres widgets Positionnement : setPopupPosition(), center(), … DecoratedPopupPanel : décore aussi le centre UIObject Widget Panel PopupPanel Decorated PopupPanel SimplePanel
  • 115. DialogBox Les boîtes de dialogues Implémente HasText (le titre appelé &quot;Caption&quot;) Implémente HasHTML (le titre peut être HTML) SimplePanel donc setWidget(Widget) Renseigner son contenu avec un Panel En géréral ajouter des boutons de fermeture Invoquer la méthode hide() Mais &quot;autoHide&quot; et &quot;modal&quot; sont héritées Méthodes liées aux événements souris Méthodes onMouse[Enter,Move, Down, Up, Leave] Typiquement utiles pour la gestion d'un menu UIObject Widget Panel PopupPanel Decorated PopupPanel DialogBox SimplePanel
  • 117. ScrollPanel Placer un widget dans une zone scrollable Affiche une partie de ce widget contenu Utilise des scrollbars pour représenter la partie visible Propose Propriété &quot;scrollPosition&quot; : la position verticale Propriété &quot;HorizontalScrollPosition&quot; : horizontale Méthodes pour scroller : scrollToBottom(), scrollToRight(), … Méthodes pour indiquer la dimension : setWidth(), setHeight() Méthode setAlwaysShowScrollBars() : masquer les scrollbars Méthode ensureVisible(UIObject) : scroll pour rendre visible UIObject Widget Panel ScrollPanel SimplePanel
  • 118. HorizontalSplitPanel Dispose deux widgets horizontalement Barre de séparation permet de redimensionner Propose Propriétés &quot;leftWidget&quot; et &quot;rightWidget&quot; Propriétés &quot;startOfLineWidget&quot; et &quot;endOfLineWidget&quot; Méthode isResizing() : redimensionnement en cours ? Méthode setSplitPosition(String) : redimensionner UIObject Widget Panel Horizontal SplitPanel
  • 119. VerticalSplitPanel Dispose deux widgets verticalement Barre de séparation permet de redimensionner Propose Propriétés &quot;bottomWidget&quot; et &quot;topWidget&quot; Méthode isResizing() : redimensionnement en cours ? Méthode setSplitPosition(String) : redimensionner UIObject Widget Panel Vertical SplitPanel
  • 120. Intégrer GWT dans une page HTML On peut ajouter du code HTML dans la page Ressources dans le répertoire &quot;public&quot; sont copiées On peut les utiliser directement dans la page HTML Exemple ajout d'une image dans le <body> de la page <img src=&quot;images/logo.png&quot; /> Associer des RootPanel aux éléments de la page Nécessite que ces éléments soient identifiés (attribut id) RootPanel.get(&quot;xxx&quot;) TP 6
  • 121. Hiérarchie partielle (Composite) UIObject Widget Composite CaptionPanel TabPanel DisclosurePanel SuggestBox DecoratedTabPanel TabBar DecoratedTabBar
  • 122. Widget : Composite Racine des widgets &quot;composite&quot; Des widgets constitués de plusieurs parties Garder une certaine intégrité du composite Souvent pour construire ses propres widgets On en hérite et on compose avec des widgets existants En gérant spécifiquement les événements (qu'on verra plus tard) Toujours invoquer initWidget() dans le constructeur UIObject Widget Composite
  • 123. Widget : CaptionPanel Cadre avec label autours d'un composant Le label peut être texte ou HTML Implémente HasWidgets Mais n'en contient qu'un seul Propose Propriétés &quot;captionText&quot; et &quot;captionHTML&quot; UIObject Widget Composite CaptionPanel
  • 124. Widget : DisclosurePanel Contient &quot;header&quot; et widget escamotable Cliquer sur le &quot;header&quot; bascule la visibilité &quot;header&quot; peut être Widget ou String Implémente HasAnimation et HasWidgets Mais n'en contient qu'un seul Propose Propriété &quot;header&quot; (Widget) Propriété &quot;contents&quot; (Widget) Propriété &quot;open&quot; (boolean) UIObject Widget Composite DisclosurePanel
  • 125. Widget : SuggestBox Un champs de saisie avec suggestion Propose dynamiquement une liste en cours de saisie Implémente HasText, HasAnimation, HasFocus Suggestions proviennent d'un SuggestOracle Une classe permettant de proposer une liste de suggestions Par défaut, MultiWordSuggestOracle Facile à renseigner : ajouter des string Propose Propriété &quot;text&quot; (vient du HasText) : le texte du champs Propriété &quot;suggestOracle&quot; : l'oracle qui va proposer les suggestions Propriété &quot;limit&quot; : limite le nombre de suggestions Méthode setPopupStyleName(String) : le style CSS du popup UIObject Widget Composite SuggestBox
  • 126. Widget : TabBar, DecoratedTabBar Une barre d'onglets (utilisée avec TabPanel) Onglet de type texte, HTML ou Widget Sélection gérée par indice Propose Méthodes add et insert pour les 3 types Méthodes getTabCount() et removeTab(int) Méthodes getSelectedTab() et selectTab(int) Méthodes getTabText(int) et setTabText(int, String) Méthodes getTabHTML(int) et setTabHTML(int, String) Méthodes pour gérer les événements DecoratedTabBar ajoute la décoration (coins arrondis) UIObject Widget Composite Decorated TabBar TabBar
  • 127. Widget : TabPanel Gestion d'onglets Composite agrégeant un TabPanel et un DeckPanel Montre le widget associé à un &quot;tab&quot; Implémente HasAnimation, IndexedPanel, HasWidgets UIObject Widget Composite Decorated TabPanel TabPanel
  • 128. Autres composants Projets open sources proposent d'autres widgets Calendrier, table triée, calculatrice, panel de dessin, bulle d'aide,… Widgets wrappant des librairies JavaScript existantes Google Map API Google Search API Scriptaculous Ext-GWT GWT-Ext SmartGWT Widget pour intégrer du SVG (Scalar Vector Graphics) Intégration de graphiques vectoriels
  • 129. S'abstraire du JavaScript ? Philosophie générale mais pas toujours possible Besoin parfois d'intégrer des librairies ou des effets JavaScript Dangers de l’encapsulation de librairies JavaScript Sympa mais souvent un seul développeur Pas toujours bien développée ou adaptée à la philosophie GWT Exemple : arrêt du support GWT-Ext par le changement de licence de ext-js On retombe dans les problèmes de compatibilité de navigateur et de version Privilégier les librairies &quot;pures GWT&quot; Plutôt que les encapsulations de librairies JavaScript Garder à l’esprit que JavaScript = Assembleur du web Qui intègrerait des librairies en assembleurs dans ses applis ? Même dans le monde du jeu vidéo ça se fait de moins en moins
  • 131. Gestion de l’internationalisation Couvre plusieurs aspects Configuration de l'application Formatage des nombres et monnaies Traduction des messages et libellés L'approche de GWT est originale Ne pas gérer ces problèmes dynamiquement mais à la compilation Générer un fichier JavaScript pour chaque locale Technique récurrente de GWT : le &quot;DeferredBinding&quot;
  • 132. DeferredBinding Technique pour pallier l'absence de &quot;dynamic binding&quot; En clair : pas de ClassLoader en JavaScript Implique de tout charger et utiliser ce qui convient Typiquement gestion des spécificités des navigateurs, des locales, … GWT gère autrement Fichier spécifique pour chaque navigateur et pour chaque locale Exemple : support de 5 navigateurs et 3 langues produit 15 fichiers différents On peut ajouter son propre axe de variance Exemple intranet / internet GWT gère automatiquement ces &quot;permutations&quot; En pratique : utiliser les méthodes de la classe GWT GWT.create(Interface) : obtenir une implémentation d'une interface
  • 133. I18n : configuration Déclaration dans le fichier de description de module Déclarer une dépendance vers le module i18n Déclarer les locales supportées Test avec le mode &quot;Hosted&quot; Ajouter &quot;?locale=fr&quot; à la fin de l'URL Utiliser le bouton Go (Refresh ne convient pas) <module> <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.i18n.I18N'/> <extend-property name=&quot;locale&quot; value=&quot;fr&quot;/> … </module>
  • 134. NumberFormat La classe pour formater des nombres et monnaies Méthode format(double) pour formater une valeur Méthode parse(String) pour décoder une chaîne Méthode statiques pour obtenir les formats standards Décimal : getDecimalFormat() Pourcent : getPercentFormat() Scientifique getScientificFormat() Monnaie : getCurrencyFormat() Possibilité de construire son propre format (règles assez classiques) Méthode getFormat(String, String) (voir NumberFormat dans la javadoc) NumberFormat fmt1 = NumberFormat.getDecimalFormat(); double value1 = 12345.6789; String formatted = fmt1.format(value1); double value2 = fmt1.parse(&quot;12345.6789&quot;); NumberFormat fmt2 = NumberFormat.getFormat(&quot;000000.000000&quot;); formatted = fmt2.format(value1);
  • 135. DateTimeFormat La classe pour formater les dates Méthodes format() pour formater une Date Méthode parse() pour décoder (s'accomode des dates invalides) Méthode parseStrict() pour décoder en refusant les dates invalides Variante pour modifier une Date existante Formats standards pour les Date, Time et DateTime getFullDateFormat(), getFullDateTimeFormat(), getFullTimeFormat() Variantes pour Long, Medium et Short Format spécifique avec getFormat(pattern) Règles classiques (voir DateTimeFormat dans javadoc)
  • 136. Gestion des messages Similaire aux fichiers de properties Stoquer des strings et nombres dans des fichiers Y accéder depuis l'application Deux mécanismes Inclusion statique (à la compilation) Inclusion dynamique (à l'exécution)
  • 137. I18n : interface Constants Déclarer une interface héritant de Constants Créer des méthodes d'accès à l'information Créer les fichiers .properties AppConstants.properties AppConstants_fr.properties Utiliser le DeferredBinding GWT.create() Implémentation à partir du fichier properties adéquat Autant de fichiers que de locales Penser à déclarer les locales Penser à écrire en UTF8 Plus simplement, utiliser le script i18nCreator Créer l'interface public interface MySettings extends Constants { String welcomeMsg(); String logoImage(); } Dans MySettings.properties welcomeMsg = Bonjour logoImage = /images/logo.jpg Utilisation dans le code MySettings s = GWT.create( MySettings.class); String msg = s.getWelcomeMsg();
  • 138. I18n : interface ConstantsWithLookup Même principe mais ajoute une méthode de lookup Permet de rechercher dans les constantes Méthode getString(String) A éviter car ne permet pas le &quot;pruning&quot; C'est-à-dire la suppression des constantes non utilisées
  • 139. I18n : interface Messages Même mécanisme mais avec des paramètres Hériter de l'interface Messages Option du i18nCreator Dans MySettings.properties welcomeMessage = Bonjour {0} {1} logoImage = /images/logo.jpg Interface correspondante public interface MySettings extends Constants { String welcomeMessage(String nom, String prenom); String logoImage(); } Utilisation dans le code MySettings settings = GWT.create(MySettings.class); String msg = settings.getWelcomeMessage( login.getNom(), login.getPrenom());
  • 140. (Dés)Avantages de l'inclusion statique Inclus dans le code compilé Aussi performant qu'une constante en dur Le compilateur optimise en faisant des &quot;inlines&quot; Seuls les messages utilisés sont embarqués Gros fichiers de propriétés institutionnels ne pénalisent pas l'appli Mais Génère beaucoup de fichiers si beaucoup de locales supportées Parfois on a besoin de valeurs plus dynamiques
  • 141. I18n : inclusion dynamique Classe Dictionary N'utilise pas de fichier de propriétés Données dans le HTML, sous forme d'objet JavaScript Données ne sont plus fixées à la compilation mais au runtime Lecture par la méthode Dictionary.getDictionary(String) var MySettings = { welcomeMessage: &quot;Bienvenue&quot;, logoImage: &quot;/images/logo.jpg&quot; }; Dictionary settings = Dictionary.getDictionary(&quot;MySettings&quot;); TP 7
  • 143. Les styles CSS (1) Rappel (pour plus d'info http://fr.selfhtml.org) Sert à séparer la présentation du contenu HTML (style) Forme : sélecteur { propriété: valeur } CSS1 : environ 50 propriétés CSS2 : 70 de plus Selecteurs possibles <H1> => H1 { } <… class=&quot;grand&quot; … => .grand { } <… id=&quot;titre&quot; … => #titre Peuvent se combiner : H1.grand = éléments H1 de classe &quot;grand&quot; Pseudo classe : exemple a.link = lien (balise <a>) pas encore visité H1 { text-align: center } .grand { font-size: 20pt } #titre { color: red } H1.grand { color: blue }
  • 144. Les styles CSS (2) Peuvent se combiner pour plus de concision Regrouper des sélecteurs Regrouper des propriétés Héritage Styles des éléments englobants Sélectionner Séparer avec un espace H1, H2, H3 { font-style: bold } H1 { color: green; text-align: center; } --- <BODY> <H1>Un exemple</H1> <P>Avec un <STRONG>paragraphe</STRONG> </P> </BODY> --- /* bleu pour contenu du BODY */ BODY { color: blue } /* rouge pour STRONG dans P */ P STRONG { color: red }
  • 145. Les styles CSS (3) Formatage d'écriture Plusieurs attributs Famille, Style, Variante Taille, Poids, Etirement Forme simplifiée Espace entre les valeurs Surcharge partielle Styles présents dans : HTML, fichiers CSS, config navigateur, préférences utilisateur Firefox + FireBug sont nos amis H1 { font-family: 'Times New Roman', serif; font-style: italic; font-variant: normal; font-size: large; font-weight: bold; font-stretch: expanded; } H2 { font: Times 13px bold; } H3 { font-weight: bold }
  • 146. Style des widgets Méthode setStyleName() pour affecter un style Indiquer le nom du style en paramètre (String) Nécessite la présence du nom dans le fichier de styles Préfixé par &quot;.&quot; (oubli fréquent) Lien vers la feuille de styles Dans le HEAD du HTML : <link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot;> Ou plutôt dans le fichier module : <stylesheet src=&quot;styles.css&quot;/> Mieux car lié à l'appli et non au fichier HTML Dans le code : Dans le fichier de styles : widget.setStyleName(&quot;special&quot;); .special { float: right; margin: 5px; }
  • 147. Style par défaut Chaque widget dispose d'un style spécifique Formé par convention : [projet]-[widget] Exemple : gwt-TextBox (style des boites de texte) Attention au préfixe &quot;.&quot; On peut modifier ces styles dans son fichier de styles Fichier public/App.css généré par l'applicationCreator
  • 148. Thèmes Installation propose trois thèmes Standard, Chrome et Dark Configuré dans le fichier de description de module (&quot;App.gwt.xml&quot;) Existe en version RTL (lecture de droite à gauche) <inherits name=&quot;com.google.gwt.user.theme.dark.DarkRTL&quot;/> Ces thèmes produisent un fichier &quot;.css&quot; On le retrouve dans le répertoire gwt de l'appli compilé Exemple : gwt/standard/standard.css pour le thème standard C'est le fichier qui précise les styles par défaut
  • 149. Modification du style UIObject propose des méthodes liées au style Méthode setStyleName(String) : permet d'affecter un style Remplace le style existant Utilisé comme une classe CSS => préfixe &quot;.&quot; dans les fichiers CSS L'intérêt des styles est de se combiner Pour combiner des effets graphiques, pour placer, … GWT propose 3 notions simplifiant cette combinaison Style primaire Style secondaire Style dépendant
  • 150. Style primaire La classe de style CSS pour un UIObject Chaque widget dispose de son style par défaut Forme &quot;gwt-&quot; suivi de la classe du widget (ex: gwt-Label) On peut changer ce style Avec setStylePrimaryName(String) Ou avec setStyleName(String) Subtile différence qu'on comprendra dans deux minutes
  • 151. Style secondaire Un widget peut se voir affecter plusieurs styles Ajouter avec addStyleName(String) Supprimer avec removeStyleName(String) Séparation par un espace dans attribut class <… class=&quot;style1 style2&quot; …> Permet de combiner des effets dynamiquement Exemple : ajout d'une bordure rouge autour d'un widget en erreur
  • 152. Style dépendant Un style secondaire un peu spécial Caractérise une propriété, un état du composant Positionné avec addStyleDependentName(String) Ou plutôt avec des méthodes prévues (setReadonly()) Concatène le style primaire, un tiret et le style dépendant Exemple : .gwt-TextBox-readonly Style spécifique de boite de texte dans le cas readonly Conservé en cas de changement de style primaire Avec setStyleName => on efface tout Avec setStylePrimaryName => on renomme TP 8
  • 154. Le modèle événementiel Navigateurs reçoivent les événements (clavier, souris) Puis les redirigent vers les éléments du DOM Deux modes possibles (bubbling ou capture) W3C impose aux navigateurs de respecter les 2 modes GWT masque et propose un modèle généralisé Document Elément2 Element1 Document Elément2 Element1 Event bubbling (modèle Internet Exporer) Event capture (modèle Netscape)
  • 155. Event Représente un événement natif (du navigateur) Une classe &quot;opaque&quot; Encapsule un objet JavaScript Propose des constantes pour les types d'événement Propose des méthodes pour tester l'événement Propose quelques méthodes un peu spécifiques
  • 156. Interface EventListener Ecouter les événements du navigateur Ceux qui arrivent sur les widgets via le DOM Seules les sous-classes de Widget devraient l'implémenter Le widget s'enregistre auprès du DOM Dans le onAttach() (vu précédemment) Méthode DOM.setEventListener(Element, EventListener) Doit déclarer le type d'événements qu'il consomme Méthodes sinkEvents() et unsinkEvents() Méthode onBrowserEvent(Event) C'est elle que les widgets vont redéfinir pour nous masquer tout ça
  • 157. Interface EventPreview Listener pour &quot;prévisualiser&quot; les événements Capture les événèments et permet de les annuler Méthode onEventPreview(Event) : retourne false pour annuler Typiquement implémenté par les DialogBox Capturer les événéments sur les autres widgets Tant que le popup est ouvert Et les annuler Méthodes statiques de la classe Event Pour installer : Event.addEventPreview() Pour désinstaller : Event.removeEventPreview()
  • 158. Schéma général SourcesConceptEvents -addConceptListener -removeConceptListener ConceptListener -onEtat1(…) -onEtat2(…) ConceptListenerCollection -fireEtat1(…) -fireEtat2(,…) ConceptListenerAdapter -onEtat1(…) { } -onEtat2(…) { } Widget Reçoit des Event du DOM, les retraduit en &quot;Concept&quot; en invoquant les &quot;fire&quot; MyListener1 -onEtat1(…) { … } -onEtat2(…) { … } MyListener2 -onEtat1(…) Interface Class implémente Class contient un Class hérite de Marque la capacité de contenir des listeners Simplifie la gestion de la collection de listeners en propageant les &quot;fire&quot; (invoque les &quot;on&quot;) Réagit aux événements Les méthodes reçoivent le widget en paramètre et éventuellement d'autres valeurs Marque un listener Simplifie si méthodes &quot;on&quot; nombreuses (implémentation vide) Ne redéfinit pas toutes les méthodes &quot;on&quot; Classe développée
  • 159. Exemple avec Button et Click SourcesClickEvents -addClickListener -removeClickListener ClickListener -onClick(Widget) ClickListenerCollection -fireClick(Widget) Button MyClickListener() { public void onClick(Widget) { Window.alert(&quot;Click !&quot;); } } Pas de ClickListenerAdapter (une seule méthode dans l'interface)
  • 160. Interface ClickListener Interface de listener d'un événement de type &quot;click&quot; Réagir à un clic sur le widget Propose la méthode onClick(Widget) Enregistrer auprès d'un SourcesClickEvents La plupart des widgets
  • 161. Interface LoadListener Interface de listener pour un événement 'load' Typiquement chargement d'image Hérite de java.util.EventListener Réagir aux événements de chargement d'un widget Méthode onLoad(Widget) Chargement terminé avec succès Méthode onError(Widget) Chargement vient d'échouer Enregistrer auprès d'un SourcesLoadEvents Uniquement Image
  • 162. Interface ChangeListener Interface de listener d'un événement de type &quot;change&quot; Réagir à une modification du widget Propose la méthode onChange(Widget) Enregistrer auprès d'un SourcesChangeEvents Typiquement les TextBox et les ListBox
  • 163. Interface FocusListener Interface de listener d'un événement de focus Réagir à la prise ou perte de focus sur le widget Propose les méthodes onFocus(Widget) et onLostFocus(Widget) Enregistrer auprès d'un SourcesFocusEvents Les FocusWidget bien sûr mais aussi FocusPanel, SuggestBox, …
  • 164. Interface KeyboardListener Interface de listener des événements clavier Réagir à l'enfoncement/relachement des touches du clavier Méthodes onKeyDown, onKeyPress, onKeyUp Recoivent le widget source, le caractère et le modificateur (ALT, SHIFT, CTRL) Constantes KEY_UP, KEY_TAB, KEY_ENTER, KEY_ESCAPE, … MODIFIER_ALT, MODIFIER_CTRL, MODIFIER_META, MODIFIER_SHIFT Enregistrer auprès d'un SourcesKeyboardEvents La plupart des widgets
  • 165. Interface MouseListener Interface de listener des événements souris Réagir à l'enfoncement/relachement des boutons de la souris Réagir à l'entrée, survol, sortie de la souris dans la zone du widget Méthodes onMouseDown, onMouseUp, onMouseMove Reçoivent le widget source, les coordonnées x et y de la souris Méthode onMouseEnter, onMouseLeave Reçoivent seulement le widget Enregistrer auprès d'un SourcesMouseEvents Les Label, HTML, Image, …
  • 166. Interface MouseWheelListener Interface de listener de la molette de la souris Réagir à l'utilisation de la molette de la souris Méthodes onMouseDown, onMouseUp, onMouseMove Reçoivent le widget source, les coordonnées x et y de la souris Méthode onMouseWheel(Widget, MouseWheelVelocity) Le MouseWheelVelocity contient les informations de direction et delta Enregistrer auprès d'un SourcesMouseWheelEvents Les Label, HTML, Image, …
  • 167. Interface PopupListener Interface de listener spécifique des PopupPanel Réagir à la fermeture d'un popup (menu, dialog, …) Méthode onPopupClosed(PopupPanel, boolean) Reçoit le panel et un booléen &quot;autoClosed&quot; Le booléen indique si le popup s'est fermé automatiquement ou par programme Enregistrer auprès d'un SourcesPopupEvents PopupPanel et ses sous-classes (dont DialogBox)
  • 168. Interface ScrollListener Interface de listener spécifique des ScrollPanel Réagir au déplacement des barres de défilement Méthode onScroll(Widget, int, int) Reçoit le widget et les positions horizontale et verticale Enregistrer auprès d'un SourcesScrollEvents ScrollPanel uniquement
  • 169. Interface TabListener Interface de listener spécifique des TabPanel et TabBar Réagir à la sélection d'un onglet Méthodes onTabSelected et onBeforeTabSelected Reçoivent le SourceTabEvents et l'indice de l'onglet concerné par la sélection Enregistrer auprès d'un SourcesTabEvents TabPanel uniquement
  • 170. Interface TableListener Interface de listener spécifique des tables Réagir à la sélection d'une cellule de la table Méthodes onCellClicked(SourcesTableEvents, int, int) Reçoivent le SourceTabEvents et les coordonnées de la cellule Enregistrer auprès d'un SourcesTabEvents HTMLTable et ses sous-classes (Grid et FlexTable)
  • 171. Interface TreeListener Interface de listener spécifique des arbres (Tree) Réagir à la sélection ou changement d'état d'un TreeItem Méthodes onTreeItemSelected et onTreeItemStateChanged Reçoivent le TreeItem concerné Enregistrer auprès d'un SourcesTreeEvents Tree uniquement TP 9
  • 173. Echange de données Nécessité d'échanger des données avec le serveur Chercher des données à afficher Transmettre des informations d'identification (login, password) Transmettre des données Sans nécessiter un raffraichissement de toute la page Comme le ferait un formulaire traditionnel Plusieurs technologies possibles Standard JavaScript : objet XMLHttpRequest RequestBuilder : une classe qui encapsule XMLHttpRequest GWT-RPC : échanger directement des objets Java
  • 174. Requête asynchrone Principe fondamental d'Ajax Asynchronous JavaScript And XML Ne bloque pas le navigateur Permet de faire autre chose en attendant (préparer l'affichage) Nécessite une structure d'appel particulière On ne peut pas faire un appel synchrone (appel de méthode) Mécanisme de &quot;Callback&quot; Code invoqué lorsque l'appel se termine (ou échoue) C'est un mécanisme événementiel
  • 175. RequestBuilder Encapsule l'objet XMLHttpRequest de JavaScript Plus proche du Java dans son utilisation Définit Des constantes pour les types de requête (GET, POST, …) Un constructeur (type de requête + une url) Une méthode de construction de requête (pattern &quot;builder&quot;) Prend une string (paramètres) et un RequestCallback (gestionnaire de réponse) Lance la requête (de manière asynchrone) Retourne un objet Request
  • 176. Interface Request Requête asynchrone Permet de ne pas bloquer le navigateur Attention : navigateurs limitent généralement le nombre de requêtes Objet Request permet de vérifier le status de la requête Intéressant dans le cas de requête longue Ou même de l'annuler
  • 177. Interface RequestCalback Définir un gestionnaire de réponse pour la requête Gestion événementielle car requête asynchrone Propose Méthode onResponseReceived() : gérer la réponse Méthode onError() : gérer une erreur En général, créer une classe interne anonyme Implémentant l'interface Exactement similaire à la gestion d'événement avec Swing Multiples formats de réponse possibles XML, HTML, texte brute, JSON, …
  • 178. Exemple d'appel avec RequestBuilder String url = &quot;/service/search&quot;; RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url); try { Request request = rb.sendRequest(&quot;param=arg&quot;, new RequestCallBack() { public void onResponseReceived(Request req, Response rep) { //traitement de la réponse } public void onError(Request req, Throwable exception) { //gestion d'erreur } }); } catch (RequestException e) { //gestion d'exception } TP 10
  • 179. XMLParser Importance de XML dans les échanges de données Format textuel (&quot;lisible&quot; par l'homme et la machine) Décrit et validable (DTD, schéma) GWT fournit un XMLParser Ajouter dépendance <inherits name=&quot;com.google.gwt.xml.XML&quot; /> Délègue le parsing au navigateur (efficacité car code natif) Produit un DOM (Document Object Model) Et des méthodes pour naviguer Document doc = XMLParser.parse(responseText); Element root = doc.getDocumentElement(); NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { traiter(children.item(i); } TP 11
  • 180. Impact des comm. asynchrones Améliore l'expérience utilisateur Rafraîchissement rapide de morceaux de page Remplissage dynamique de listes longues, d'arbre Rafraîchissement automatique possible … Techniquement Nécessite un codage / décodage des données Parsing et constitution des DOM (empreinte mémoire importante)
  • 181. Service GWT RPC Echanger directement des objets Permet de masquer cette phase de décodage La partie serveur est en Java et y reste (tout est possible) Plusieurs étapes Définir une interface du service Définir une implémentation du service (servlet) Définir une interface d'appel asynchrone Déclarer le servlet dans le fichier module Créer un invocateur du service (proxy) Configurer cet invocateur vers le servlet Créer un AsyncCallback pour gérer la requête Invoquer le service
  • 182. Mise en œuvre d'un service (1) Première étape : définir l'interface du service Doit hériter RemoteService Doit être dans le sous-package &quot;.client&quot; de l'application Contraintes fortes sur paramètres et valeur de retour Voir ci-après Sérialisation En bref : primitifs, String, Date, Serializable, Array et IsSerializable package com.oxiane.formation.cave.client; import com.google.gwt.user.client.rpc.RemoteService; //MyData et MyParam sont des POJOs Serializable public interface MyService extends RemoteService { MyData[] myRemoteMethod(MyParamData paramData); }
  • 183. Mise en œuvre d'un service (2) Définir une implémentation du service (servlet) Doit hériter RemoteServiceServlet Doit être dans le sous-package &quot;.server&quot; de l'application Doit implémenter l'interface du Service Doit être nommée comme le Service suffixé avec Impl Le code est complètement libre (reste sur le serveur) package com.oxiane.formation.cave.server; import com.google.gwt.user.server.rpc.RemoteServiceServlet; … import com.oxiane.formation.cave.client.MyService; public class MyServiceImpl extends RemoteServiceServlet implements MyService { public MyData[] myRemoteMethod(MyParamData paramData) { … return result; } }
  • 184. Mise en œuvre d'un service (3) Déclarer une interface d'appel asynchrone Nécessaire pour rester dans la logique Ajax Doit porter le même nom que l'interface suffixée avec &quot;Async&quot; Doit reprendre les méthodes de l'interface (pas tout à fait) Paramètre supplémentaire de type AsyncCallback<typeRetour> Type de retour void Type de retour reporté dans le type générique du AsyncCallback Attention : contraintes non explicites !!! package com.oxiane.formation.cave.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface MyServiceAsync { void myRemoteMethod(MyParamData paramData, AsyncCallback<MyData[]> callback); }
  • 185. Mise en œuvre d'un service (4) Déclaration du servlet Dans le fichier module pour tester avec le mode hosted Dans le fichier web.xml en déploiement réel Remarque le chemin est libre <servlet path='/myservice' class='com.oxiane.formation.cave.server.MyServiceImpl'/>
  • 186. Mise en œuvre d'un service (5) Créer un invocateur du service Il s'agit d'un proxy implémentant l'interface Async Utilise le &quot;DeferredBinding&quot; : GWT.create(MyService.class) Remarque Interface de retour est différente de celle demandée Idéalement le conserver en attribut pour plusieurs utilisations MyServiceAsync myServiceProxy = GWT.create( MyService.class );
  • 187. Mise en œuvre d'un service (6) Configurer le proxy Il faut le lier au servlet par l'URL Interface ServiceDefTarget GWT.getModuleBaseURL () pour obtenir l'URL Possibilité d'automatiser avec une annotation sur l'interface @RemoteServiceRelaticePath(&quot;chemin du service&quot;) Bien mettre le même chemin que dans le fichier module ((ServiceDefTarget) myServiceProxy).setServiceEntryPoint ( GWT.getModuleBaseURL () + &quot;/myservice&quot; );
  • 188. Mise en œuvre d'un service (7) Créer un gestionnaire de réponse (AsyncCallback<T>) Interface de callback Méthode onSuccess(Object result) Méthode onFailure(Throwable cause) Type générique apporte le type sur le paramètre du &quot;onSucces&quot; Comme d'habitude, on peut faire une classe anonyme AsyncCallback<MyData[]> callback = new AsyncCallback<MyData[]>() { public void onSuccess( MyData[] result ) { //code en cas de succès } public void onFailure( Throwable caught ) { //code en cas d'erreur } };
  • 189. Mise en œuvre d'un service (8) Invoquer le service Utiliser directement les méthodes de l'interface Async AsyncCallback<MyData[]> callback = new AsyncCallback<MyData[]>() { … }; MyParamData param = new MyParamData(1); myServiceProxy.myRemoteMethod(param, callback);
  • 190. Sérialisation (1) Encoder et décoder les objets Intérêt de GWT-RPC = masquer cette phase (le plus possible) Contrainte sur les données sérialisables Types primitifs char, byte, short, int, long, boolean, float et double Leur wrapper Character, Integer, … String, Date Enumeration (mais seul leur nom est sérialisé) Les classes implémentant com.google.gwt.user.client.rpc.IsSerializable Ou java.io.Serializable (depuis GWT 1.5) Les collections et arrays de ces types
  • 191. Serialisation (2) Remarques sur les classes sérialisables Avoir un constructeur vide Mot clé &quot;transient&quot; respecté (attribut ignoré) Attributs &quot;final&quot; aussi (les marquer &quot;transient&quot; pour ne pas l'oublier) Problèmes avec les Collection telles que List et Set Nécessité de typer complètement Typage dans les commentaires dans les versions précédentes Exemple @gwt.typeArgs <java.lang.String> Utiliser les types génériques depuis 1.5 Exemple : Set<String>
  • 192. Gestion des exceptions Sérialisables aussi si contraintes respectées Services peuvent lever des exceptions Méthode AsyncCallback.onFailure() pour gérer côté client InvocationException Levée si le client ne peut pas contacter le service Ou si un problème inattendu survient IncompatibleRemoteServiceException Si le service est modifié sans que le client soit au courant Recharger la page dans ce cas TP 12
  • 193. Le format JSON Un format textuel courant dans le monde JavaScript Syntaxe JavaScript correspondant à la définition d'objets Facile à utiliser Site &quot;http://www.json.org&quot; Nombreux codeur/décodeur dans différents langages Deux modes d'utilisation dans GWT L'utiliser directement dans JavaScript (JSNI) Utiliser JSONParser et la hiérarchie des JSONValue
  • 195. Utilisation de JSON Données textuelles en réponse d'une requête HTTP Analyser avec JSONParser.parse() Retourne une JSONValue (hiérarchie de classes) Propose des méthodes pour décortiquer la structure obtenue Exemple de données JSON { &quot;product&quot;: { &quot;name&quot;: &quot;Widget&quot;, &quot;company&quot;: &quot;ACME, Inc&quot;, &quot;partNumber&quot;: &quot;7402-129&quot;, &quot;prices&quot;: [ { &quot;minQty&quot;: 1, &quot;price&quot;: 12.49 }, { &quot;minQty&quot;: 10, &quot;price&quot;: 9.99 }, { &quot;minQty&quot;: 50, &quot;price&quot;: 7.99 } ] } }
  • 196. JSONValue Classe abstraite Une sous classe pour chaque type de données JSON JSONArray, JSONBoolean, JSONNull, JSONNumber, JSONObject, JSONString Méthode isXXX() pour chaque type Attention : pas une méthode de test Retourne un objet de ce type si la value est bien de ce type Retourne null sinon Méthode toString Pour obtenir une string JSON prête à envoyer
  • 197. JSONObject et JSONArray JSONObject Représente un objet JSON (une structure nom-valeur) Méthodes get(String) et set(String, JSONValue) Pour obtenir et positionner une valeur JSON par son nom Méthode size() : nombre de clés Méthodes keySet(), containsKey() Obtenir les clés et tester la présence d'une clé JSONArray Représente un tableau Méthodes get(int) et set(int, JSONValue) Pour obtenir et positionner une valeur JSON par son indice Méthode length() : longueur du tableau TP 13
  • 198. Le bouton &quot;back&quot; du navigateur Problème avec le remplacement partiel de la page Ne compte pas comme un changement de page pour le navigateur Mais l'utilisateur voit une page différente Intuitivement, l'utilisateur peut vouloir annuler En utilisant le bouton &quot;back&quot; Pas agréable de condamner le bouton back Et ne marche pas bien Solution : gérer intelligemment le bouton &quot;back&quot;
  • 199. Classe History (1) Générer des &quot;history token&quot; Pour identifier les états de l’application Par programmation History.newItem(&quot;accueil&quot;) Ou avec la classe Hyperlink Qui génère pour nous les tokens Gère des HistoryListener Méthode addHistoryListener()
  • 200. Classe HistoryListener Interface pour réagir aux boutons Back et Forward Propose une méthode onHistoryChanged() Reçoit le token en paramètre Pour remettre l’application dans l’état correspondant au token Invoquée lors de l’utilisation des boutons Créer en général une implémentation anonyme
  • 201. Fonctionnement de l’History Gestion transparente d'un &quot;frame&quot; caché html Doit être laissé dans la page HTML Le navigateur recharge le contenu du frame caché Il &quot;voit&quot; un chargement de page, l'ajoute dans son historique Le listener est sollicité (méthode onHistoryChanged()) L'application réagit en conséquence en fonction du token Pas de magie C’est au développeur de prendre en compte la cohérence Par exemple annuler des données soumises TP 14
  • 203. Log Problème récurrent avec les applications Web Non Ajax : toute action se passe sur le serveur => log possible Ajax : beaucoup d'actions mais impossible d'écrire sur un fichier On pourrait utiliser un service du serveur Besoin des log pour la mise au point Il existe des loggers JavaScript (intégration possible) Moins nécessaire avec mode Hosted (debug directement en Java) Possibilité d'utiliser le système de log du mode Hosted GWT.log() avec un message et un Throwable (ou null)
  • 204. Utilisation d’images Widget pour afficher une image Indiquer l'URL complète ou bien relative au répertoire public Mode unclipped : image affichée en entier Mode clipped : image affichée partiellement Spécifier des coordonnées à la construction Source d'événements Click, Load, Mouse et MouseWheel Permet d'abonner des listeners pour réagir Méthode statique prefetch() pour optimiser Demander au navigateur de pré-charger l'image
  • 205. ImageBundle Problèmes avec le chargement de nombreuses images Chaque image recherchée coûte un appel vers le serveur Problème de bande passante Limitation du nombre de connexions simultanées vers le serveur Technique d'optimisation : regrouper les images En une seule grande image Permet de rapatrier la grosse image en un seul appel au serveur Possible car on peut afficher une partie d'une image ImageBundle simplifie cette technique
  • 206. Mise en œuvre de ImageBundle Même principe que Constants : faire une interface Hériter de ImageBundle Déclarer des méthodes AbstractImagePrototype xyz(); Mettre le fichier image dans le répertoire de l'interface Extensions supportées automatiquement : .png, .gif ou .jpg Utiliser le DeferredBinding (GWT.create(MesImages.class) Récupérer les prototypes avec les méthodes xyz() Créer l'image avec la méthode createImage()
  • 207. Intégration Java EE Limitation de JavaScript Interdiction d’adresser un autre site que celui d’origine Une sécurité dans les navigateurs pour éviter le code malicieux Impossible d’adresser des requêtes JEE vers un autre serveur Implique de passer par un proxy sur son serveur Le JavaScript appelle son serveur qui fera le relai
  • 208. Déployer son application Essentiellement reconstituer un fichier WAR Avec l’application compilée bien sûr Copier les fichiers du répertoire www dans un répertoire temporaire Recréer la structure de répertoire WEB-INF et créer le web.xml Pensez à ajouter le code serveur dans le cas GWT RPC Compiler les servlets avec javac, copier et déclarer dans le web.xml En accord avec les url indiquées pour les proxy GWT RPC Copier le gwt-servlet.jar dans le WEB-INF/lib Zipper et renommer en .war En général, utilisation d’un script Ant pour faire tout ça
  • 209. Tester avec Junit (1) Test = démarche de génie logiciel importante Améliore les garanties de succès pour un projet Intégration de JUnit dans GWT Pas de nécessité de développer des outils de test spécifiques Permet de tester ses objets et méthodes Permet de tester les appels RPC et leurs résultats Dans les deux modes (hosted et web) Mise œuvre Faire une sous-classe de GWTTestCase Une sous-classe de TestCase de junit Implémenter la méthode getModuleName() Le script junitCreator permet d’automatiser ça
  • 210. Tester avec Junit (2) Création du TestCase Création des scripts de lancement Reste plus qu’à coder ses méthodes de tests Méthodes standards de JUnit junitCreator -junit &quot;C:\junit.jar&quot; -module com.google.gwt.sample.stockwatcher.StockWatcher -eclipse StockWatcher com.google.gwt.sample.stockwatcher.client.StockWatcherTest TP 16
  • 211. Présentation de JSNI Ecrire des méthodes natives en JavaScript Méthode java native Commentaire /*- -*/ pour spécifier le code Code recopié par le compilateur Permet aussi de Typer des méthodes JavaScript Appeler du code JavaScript depuis Java et vice versa Lire et écrire des attributs Java depuis JavaScript public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
  • 212. Manipulation d'objets Java (1) JSNI permet d’invoquer du code Java Mais problème de typage Notation pour spécifier les méthodes et les types Invocation de méthode [instance-expr.]@class-name::method-name(param-signature)(arguments) Avec [instance-expr.] = Nom d’attribut ou this ou rien pour statique Signatures des paramètres suivent les règles JNI (voir ci après) Accès à un attribut [instance-expr.]@class-name::method-name
  • 213. Manipulation d’objets Java (2) Syntaxe JNI des signatures de méthode Signature Type Java ============================================ Z boolean B byte C char S short I int J long F float D double L nom/complet/de/classe; classe [ type type[] Exemple public class JSNIExample { void a(String s) { // code Java } } Invoqué en JavaScript avec this.@com.oxiane.JSNIExample::a(Ljava/lang/String;)(s);
  • 214. Passage d’objets entre les deux mondes Les types primitifs passent sans problème Sauf long qui n’est pas supporté par JavaScript Objet JavaScriptObject Objet opaque pour le monde Java Ne peut être utilisé que par JavaScript (en le passant en argument) Objet Java Objet opaque pour le monde JavaScript
  • 215. JavaScript Overlay Type Technique pour encapsuler un objet JavaScript Dans une classe Java Plus facile à utiliser par le monde Java Définir une sous-classe de JavaScriptObject Avec un constructeur sans argument protected Des méthodes natives pour accéder aux infos de l’objet On peut même rajouter des vraies méthodes java Définir des méthodes statiques natives Dans d’autres classes Retournent des instances
  • 216. GWTShell La classe qui lance le mode &quot;hosted&quot; L'applicationCreator génère un script &quot;App-shell&quot; GWTShell [-port numPort | &quot;auto&quot;] execute un tomcat sur le port (défaut 8888) [-noserver] pas de serveur (si serveur externe utilisé) [-whitelist &quot;list&quot;] URLs externes autorisées (liste de regex) [-blacklist &quot;list&quot;] URLs externes interdites (liste de regex) [-logLevel niveau] ERROR, WARN, INFO*, TRACE, DEBUG, SPAM ou ALL [-gen répertoire] répertoire des fichiers temps de compilation [-out répertoire] répertoire de sortie des fichiers [-style style] OBF[USCATED]*, PRETTY ou DETAILED [-ea] active la vérification des assertions [url] URL à lancer expressions régulières séparées par &quot; &quot; ou &quot;,&quot; ^http[:][/][/]www[.]site[.]com * = Valeur par défaut
  • 217. GWTCompiler La classe qui compile en JavaScript L'applicationCreator génère un script &quot;App-compile&quot; GWTCompiler [-logLevel niveau] ERROR, WARN, INFO*, TRACE, DEBUG, SPAM ou ALL [-gen répertoire] répertoire des fichiers temps de compilation [-out répertoire] répertoire de sortie des fichiers [-treeLogger] log sous forme arborescente [-style style] OBF[USCATED]*, PRETTY ou DETAILED [-ea] active la vérification des assertions [-validateOnly] valide le code source sans compiler module nom du module à compiler * = Valeur par défaut
  • 218. Exemple de JavaScript Overlay Données JSON obtenues en JavaScript var jsonData = [ { &quot;FirstName&quot; : &quot;Jimmy&quot;, &quot;LastName&quot; : &quot;Webber&quot; }, { &quot;FirstName&quot; : &quot;Alan&quot;, &quot;LastName&quot; : &quot;Dayal&quot; }, ]; class Customer extends JavaScriptObject { protected Customer() { } public final native String getFirstName() /*-{ return this.FirstName; }-*/; public final native String getLastName() /*-{ return this.LastName; }-*/; public final String getFullName() { return getFirstName() + &quot; &quot; + getLastName(); } } Dans une autre classe private native Customer getFirstCustomer() /*-{ return $wnd.jsonData[0]; }-*/; TP 17
  • 219. Evolutions de la 1.6 (1) Nouvelle version 1.6 sortie Q1 2009 Accélérer la compilation (problème récurrent) Bénéficier des architectures multicores pour paralléliser la compilation Changement de structure des projets Structure WAR pour simplifier le déploiement Impact sur les outils Jetty à la place du tomcat embarqué (plus léger, plus rapide) Nouveau modèle événementiel à base de Handler Tous les listeners vont être remplacés par des Handler Impact sur le code existant Prise en compte des spécificités des chaînes de caractères (optim) Différence de performance sur les join, concat et += selon les navigateurs
  • 220. Evolutions de la 1.6 (2) Suite GWT.runAsync : découper une appli en plusieurs fichiers Devenait nécessaire pour le développement de grosses applications Mode &quot;hosted&quot; Out-of-process : directement dans le navigateur UIBinder : charger des descriptions XML d'écrans plutôt que coder ClientBundle : regrouper des ressources spécifiques à un client Amélioration du support des outils de Mapping Objet Relationnel
  • 222. Conclusion Un toolkit puissant et original Une approche différente du web Des techniques très bien pensées Optimisation systématique Disponibilités croissantes de bibliothèques Mais Encore en évolution Attention au choix des bibliothèques Trop puissant ?