<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog de GreenIvory &#187; GWT</title>
	<atom:link href="http://blog.greenivory.fr/tag/gwt/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.greenivory.fr</link>
	<description>Développement agile sur technologies web 2.0</description>
	<lastBuildDate>Fri, 03 Feb 2012 11:23:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>GWT : utiliser l&#8217;API Activity/Place pour gérer la navigation dans vos applications web</title>
		<link>http://blog.greenivory.fr/2011/10/21/gwt-activity-place-navigation-applications-web/</link>
		<comments>http://blog.greenivory.fr/2011/10/21/gwt-activity-place-navigation-applications-web/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 15:13:37 +0000</pubDate>
		<dc:creator>Frédéric</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[navigation]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://blog.greenivory.fr/?p=1972</guid>
		<description><![CDATA[Beaucoup d&#8217;applications web sont désormais basées sur AJAX, et offrent ainsi une interface plus réactive et plus dynamique, en minimisant (voire supprimant) les rechargements de page : les données à affichées sont chargées en arrière-plan puis insérées dans la page web, à coup de JavaScript (manipulation du DOM). Contrairement à une page web entièrement générée [...]]]></description>
			<content:encoded><![CDATA[<div style="height:33px;" class="really_simple_share robots-nocontent snap_nopreview"><div class="really_simple_share_facebook_like" style="width:100px;">
				<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fblog.greenivory.fr%2F2011%2F10%2F21%2Fgwt-activity-place-navigation-applications-web%2F&amp;layout=button_count&amp;show_faces=false&amp;width=100&amp;action=like&amp;colorscheme=light&amp;send=false&amp;height=27" 
						scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:27px;" allowTransparency="true"></iframe>
				</div><div class="really_simple_share_google1" style="width:90px;">
					<g:plusone size="medium" href="http://blog.greenivory.fr/2011/10/21/gwt-activity-place-navigation-applications-web/" ></g:plusone>
				</div><div class="really_simple_share_twitter" style="width:110px;">
					<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" 
						data-text="GWT : utiliser l&#8217;API Activity/Place pour gérer la navigation dans vos applications web" data-url="http://blog.greenivory.fr/2011/10/21/gwt-activity-place-navigation-applications-web/" 
						data-via="" ></a> 
				</div></div>
		<div style="clear:both;"></div><p>Beaucoup d&#8217;applications web sont désormais basées sur AJAX, et offrent ainsi une interface plus réactive et plus dynamique, en minimisant (voire supprimant) les rechargements de page : les données à affichées sont chargées en arrière-plan puis insérées dans la page web, à coup de JavaScript (manipulation du DOM).</p>
<p>Contrairement à une page web entièrement générée par le serveur, cette page doit alors faire preuve d&#8217;une <em>intelligence</em> supplémentaire afin de gérer l&#8217;état de l&#8217;application à chaque instant de son utilisation. Peu importe donc la technologie employée sur le serveur, on s&#8217;attarde donc à trouver une technologie évoluée coté client, forcément basée sur JavaScript, seul langage à être embarqué dans tous les navigateurs modernes. Ont alors vu le jour de multiples<strong> framework JavaScript</strong>, tels <a href="http://jquery.com/">jQuery</a>, <a href="http://mootools.net/">MooTools</a>, <a href="http://www.prototypejs.org/">Prototype</a> ou encore <a href="http://script.aculo.us/">Scriptaculous</a>.</p>
<p>Google a tenté une approche différente en proposant un framework Java, couplé à un traducteur Java vers JavaScript. Une réelle prouesse technique, qui promet une abstraction quasi-totale du navigateur. L&#8217;avantage est que le codage se fait en Java, langage plus rigoureux que JavaScript, et ainsi plus simple à débugguer.</p>
<p>Avec GWT, l&#8217;application web, c&#8217;est une page web. S&#8217;il y a différentes vues (un formulaire de création, une liste, &#8230;), c&#8217;est via le DOM qu&#8217;on affiche les widgets qu&#8217;il faut. Mais pour le navigateur, l&#8217;URL reste la même, et si on recharge la page, la vue peut alors être perdue. De la même manière, l&#8217;utilisation du bouton Précédent dans le navigateur ne permet pas de naviguer, comme sur un site web classique. Sauf si&#8230; Si on réussit à faire croire au navigateur que l&#8217;URL a changé sans recharger la page, ça peut marcher.</p>
<h3>Les ancres dans les URL</h3>
<p>Dans une URL, on peut faire référence à un élément de la page (identifié de manière unique par un attribut <em>id</em>) en suffisant l&#8217;URL par #&lt;id de l&#8217;élément&gt;. La navigateur va alors défiler la page jusqu&#8217;à ce que l&#8217;élément concerné soit visible (s&#8217;il l&#8217;est). Cela permet de naviguer au sein d&#8217;une même page, et c&#8217;est très souvent utilisé pour une table des matières en début de page. L&#8217;avantage est que le navigateur considère tout changement derrière le caractère # d&#8217;une URL (l&#8217;ancre) comme étant une URL différente, ayant son entrée propre dans l&#8217;historique des pages visitées. En même temps, un changement d&#8217;ancre ne recharge pas la page.</p>
<h3>La classe <em>History</em> de GWT</h3>
<p>En GWT, on peut être notifié par un système d&#8217;événement d&#8217;un changement d&#8217;ancre (et donc sans que la page ne soit rechargée) et connaître le nom de l&#8217;ancre. Ainsi, on peut exécuter du code et afficher telle ou telle vue en fonction de l&#8217;ancre actuelle. La classe <em>History</em> dans GWT permet cela. Et GWT propose une technique très efficace pour gérer ces changements dans l&#8217;interface en fonction de l&#8217;URL</p>
<h3>Activity et Place</h3>
<p>GWT part du principe suivant  : à une URL correspond un affichage de l&#8217;application. Cet état (visuel) de l&#8217;application qui dépend de l&#8217;URL s&#8217;appelle une <strong>Place</strong>.</p>
<p>A cette Place, on associe généralement une <strong>Activity</strong>, c&#8217;est à dire une <strong>fonctionnalité de l&#8217;application</strong>.</p>
<p>Cette Activity va alors exécuter le code qu&#8217;il faut pour placer l&#8217;interface dans l&#8217;état voulue par l&#8217;URL.</p>
<p>Pour résumer :</p>
<ol>
<li>de l&#8217;URL (ancre, encore appelé <em>history token</em>), on déduit une <em>Place</em> via un <em>PlaceHistoryMapper</em>,</li>
<li>de cette <em>Place</em>, on déduit une <em>Activity</em> via un <em>ActivityMapper</em>.</li>
</ol>
<p style="text-align: center;"><img class="size-full wp-image-1981 aligncenter" title="GWTPlaceActivity" src="http://blog.greenivory.fr/wp-content/uploads/2011/10/GWTPlaceActivity.png" alt="" width="133" height="214" /></p>
<p><strong>Dans la pratique</strong>, cela se traduit se cette manière-là.</p>
<p style="text-align: center;"><img class="size-full wp-image-1987 aligncenter" title="GWTActivityPlaceProjectStructure" src="http://blog.greenivory.fr/wp-content/uploads/2011/10/GWTActivityPlaceProjectStructure.png" alt="" width="255" height="225" /></p>
<ul>
<li>une classe par Place (ici : <em>EditPlace</em> et <em>ListPlace</em>),</li>
<li>une classe par Activity (ici : <em>EditActivity</em> et <em>ListActivity</em>),</li>
<li>un ActivityMapper (ici <em>AppActivityMapper</em>),</li>
<li>un PlaceHistoryMapper (ici <em>AppPlaceHistoryMapper</em>),</li>
<li>un point d&#8217;entrée (ici <em>Index</em>),</li>
<li>une Factory (ici <em>ClientFactory</em>) pour quelques objets dont on a souvent besoin.</li>
</ul>
<h4>Dans notre point d&#8217;entrée (<em>Index.java</em>)</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Nous avons besoin d'un panneau dans lequel vont s'afficher les différentes</span>
<span style="color: #666666; font-style: italic;">// vues de l'application.</span>
<span style="color: #666666; font-style: italic;">// Ici, ce sera la page entière, mais on pourrait n'avoir qu'une partie</span>
<span style="color: #666666; font-style: italic;">// centrale par exemple, avec des menus globaux autour qui seraient toujours</span>
<span style="color: #666666; font-style: italic;">// là.</span>
SimplePanel rootPanel <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimplePanel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
RootLayoutPanel.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>rootPanel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Le bus où tous les événements &quot;métiers&quot; de l'application seront déclenchés.</span>
EventBus eventBus <span style="color: #339933;">=</span> ClientFactory.<span style="color: #006633;">INSTANCE</span>.<span style="color: #006633;">getEventBus</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Un peu de plomberie...</span>
PlaceController placeController <span style="color: #339933;">=</span> ClientFactory.<span style="color: #006633;">INSTANCE</span>.<span style="color: #006633;">getPlaceController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
ActivityManager activityManager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ActivityManager<span style="color: #009900;">&#40;</span>
   <span style="color: #000000; font-weight: bold;">new</span> AppActivityMapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, eventBus
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
activityManager.<span style="color: #006633;">setDisplay</span><span style="color: #009900;">&#40;</span>rootPanel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
AppPlaceHistoryMapper historyMapper <span style="color: #339933;">=</span> GWT.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>AppPlaceHistoryMapper.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
PlaceHistoryHandler historyHandler <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PlaceHistoryHandler<span style="color: #009900;">&#40;</span>historyMapper<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Place par défaut si rien n'est spécifié dans l'URL.</span>
ListPlace defaultPlace <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ListPlace<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
historyHandler.<span style="color: #006633;">register</span><span style="color: #009900;">&#40;</span>placeController, eventBus, defaultPlace<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// On déclenche tout ça !</span>
historyHandler.<span style="color: #006633;">handleCurrentHistory</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>Il est obligatoire d&#8217;avoir <strong>un seul conteneur</strong> qui sera la destination des différentes vues de l&#8217;application.</li>
<li>Ces initialisations sont certes un peu fastidieuses, mais elles peuvent être copiées/collées d&#8217;un projet à un autre (ou mutualisées, pourquoi pas, dans la <em>ClientFactory</em>).</li>
<li>Le déclenchement réalisé sur la dernière ligne n&#8217;est pas automatique : ne l&#8217;oubliez pas !</li>
<li><em>AppPlaceHistoryMapper</em> est instancié via un <a href="http://code.google.com/webtoolkit/doc/1.6/FAQ_Client.html#Deferred_Binding">defered binding</a> (<em>GWT.create()</em>).</li>
</ul>
<h4>AppPlaceHistoryMapper :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.PlaceHistoryMapper</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.WithTokenizers</span><span style="color: #339933;">;</span>
&nbsp;
@WithTokenizers<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#123;</span>
	EditPlace.<span style="color: #006633;">Tokenizer</span>.<span style="color: #000000; font-weight: bold;">class</span>,
	ListPlace.<span style="color: #006633;">Tokenizer</span>.<span style="color: #000000; font-weight: bold;">class</span>,
<span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> AppPlaceHistoryMapper <span style="color: #000000; font-weight: bold;">extends</span> PlaceHistoryMapper <span style="color: #009900;">&#123;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>Il suffit de lister les différentes Place (en fait, leur Tokenizer) dans l&#8217;annotation @WithTokenizers.</li>
</ul>
<h4>AppActivityMapper :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.activity.shared.Activity</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.activity.shared.ActivityMapper</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.Place</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AppActivityMapper <span style="color: #000000; font-weight: bold;">implements</span> ActivityMapper <span style="color: #009900;">&#123;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> Activity getActivity<span style="color: #009900;">&#40;</span>Place place<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>place <span style="color: #000000; font-weight: bold;">instanceof</span> ListPlace<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> ListActivity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>ListPlace<span style="color: #009900;">&#41;</span> place<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>place <span style="color: #000000; font-weight: bold;">instanceof</span> EditPlace<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> EditActivity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>EditPlace<span style="color: #009900;">&#41;</span> place<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>A chaque Place, son Activity !</li>
</ul>
<h4>ClientFactory :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.event.shared.EventBus</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.event.shared.SimpleEventBus</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.PlaceController</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ClientFactory <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> EventBus eventBus<span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">private</span> PlaceController placeController<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> ClientFactory INSTANCE <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ClientFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">protected</span> ClientFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		eventBus <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimpleEventBus<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		placeController <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PlaceController<span style="color: #009900;">&#40;</span>eventBus<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> EventBus getEventBus<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> eventBus<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> PlaceController getPlaceController<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> placeController<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>Il est impératif d&#8217;utiliser toujours les mêmes instances du PlaceController et du EventBus dans toute l&#8217;application. La ClientFactory (qui est un <a href="http://fr.wikipedia.org/wiki/Singleton_(patron_de_conception)" target="_blank">singleton</a>) est donc une bonne pratique pour les contenir.</li>
</ul>
<h4>ListPlace :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.Place</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.PlaceTokenizer</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.Prefix</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #008000; font-style: italic; font-weight: bold;">/**
 * Les URLs sont du type : http://server/index.html#ancre:token.
 * 'ancre' sert à déterminer la Place à utiliser.
 * 'token' sert à transmettre des paramètres à la Place.
 * Ce token peut être vide, mais le double-point est obligatoire.
 */</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ListPlace <span style="color: #000000; font-weight: bold;">extends</span> Place <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> ListPlace<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Prefix<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;list&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// Ancre utilisée pour identifier cette Place.</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">class</span> Tokenizer <span style="color: #000000; font-weight: bold;">implements</span> PlaceTokenizer <span style="color: #009900;">&#123;</span>
&nbsp;
        @Override
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getToken<span style="color: #009900;">&#40;</span>ListPlace place<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        	<span style="color: #666666; font-style: italic;">// Retourner le token en fonction des paramètres de la place.</span>
        	<span style="color: #666666; font-style: italic;">// Ici, jamais de paramètre, donc toujours chaîne vide</span>
        	<span style="color: #666666; font-style: italic;">// (mais jamais null !).</span>
        	<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        @Override
        <span style="color: #000000; font-weight: bold;">public</span> ListPlace getPlace<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> token<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        	<span style="color: #666666; font-style: italic;">// En fonction du 'token' (derrière le double-point</span>
        	<span style="color: #666666; font-style: italic;">// après l'ancre), instancier la Place.</span>
        	<span style="color: #666666; font-style: italic;">// Ici, on ne gère pas de paramètres, donc on instancie</span>
        	<span style="color: #666666; font-style: italic;">// toujours une ListPlace tout simple.</span>
        	<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> ListPlace<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h4>ListActivity :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.activity.shared.Activity</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.event.shared.EventBus</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.Place</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.user.client.ui.AcceptsOneWidget</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.user.client.ui.HTML</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ListActivity <span style="color: #000000; font-weight: bold;">implements</span> Activity <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #008000; font-style: italic; font-weight: bold;">/**
	 * @param place
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> ListActivity<span style="color: #009900;">&#40;</span>Place place<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> mayStop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Retourner null pour autoriser l'arrêt de l'Activity.</span>
		<span style="color: #666666; font-style: italic;">// Retourner une chaîne non-nulle pour demander à</span>
		<span style="color: #666666; font-style: italic;">// l'utilisateur si l'Activity doit être stoppée ou non.</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onCancel()
	 */</span>
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Exécutée quand l'Activity n'est pas démarrée.</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onStop()
	 */</span>
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onStop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Exécutée quand l'Activity est arrêtée.</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#start()
	 */</span>
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> start<span style="color: #009900;">&#40;</span>AcceptsOneWidget panel, EventBus eventBus<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Code de l'Activity.</span>
		panel.<span style="color: #006633;">setWidget</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">HTML</span><span style="color: #009900;">&#40;</span>
		<span style="color: #0000ff;">&quot;Liste d'éléments | &amp;lt;a href='#edit:1'&amp;gt;Editer id=1&amp;lt;/a&amp;gt; | &amp;lt;a href='#edit:3'&amp;gt;Editer id=3&amp;lt;/a&amp;gt;&quot;</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>La méthode <em>start()</em> est indéniablement la plus importante, mais les autres sont très pratiques pour contrôler la navigation : l&#8217;utilisateur peut-il arrêter cette <strong>Activity</strong> (méthode <em>mayStop()</em>) ?</li>
</ul>
<h4>EditPlace :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.Place</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.PlaceTokenizer</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.place.shared.Prefix</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #008000; font-style: italic; font-weight: bold;">/**
 * Les URLs sont du type : http://server/index.html#ancre:token.
 * 'ancre' sert à déterminer la Place à utiliser.
 * 'token' sert à transmettre des paramètres à la Place. Peut être vide, mais le double-point est obligatoire.
 */</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> EditPlace <span style="color: #000000; font-weight: bold;">extends</span> Place <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> id<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> EditPlace<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> id<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">id</span> <span style="color: #339933;">=</span> id<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> getId<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> id<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
    @Prefix<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;edit&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// Ancre utilisée pour identifier cette Place.</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">class</span> Tokenizer <span style="color: #000000; font-weight: bold;">implements</span> PlaceTokenizer <span style="color: #009900;">&#123;</span>
&nbsp;
        @Override
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getToken<span style="color: #009900;">&#40;</span>EditPlace place<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        	<span style="color: #666666; font-style: italic;">// Retourner le token en fonction des paramètres de la place.</span>
        	<span style="color: #666666; font-style: italic;">// Ici, on s'attend à avoir l'ID en paramètre, donc on retourne une chaîne contenant l'ID de la Place.</span>
        	<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #003399;">String</span>.<span style="color: #006633;">valueOf</span><span style="color: #009900;">&#40;</span>place.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        @Override
        <span style="color: #000000; font-weight: bold;">public</span> EditPlace getPlace<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> token<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        	<span style="color: #666666; font-style: italic;">// En fonction du 'token' (derrière le double-point après l'ancre), instancier la Place.</span>
        	<span style="color: #666666; font-style: italic;">// Ici, le token contient l'ID de l'élément à éditer : nous n'avons qu'à le transformer en entier...</span>
        	<span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
        		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> EditPlace<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span>.<span style="color: #006633;">parseInt</span><span style="color: #009900;">&#40;</span>token<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        	<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">NumberFormatException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> EditPlace<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        	<span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>Il est possible de passer autant de paramètres qu&#8217;on le souhaite dans le token, pourvu qu&#8217;on le parse correctement.</li>
<li>Vous êtes libres de créer tous les paramètres nécessaires dans la Place.</li>
<li>Ne prenez pas à la légère la méthode <em>getToken()</em> : il est important qu&#8217;elle retourne le token qui permet de <strong>reconstruire une Place identique</strong> (avec les mêmes paramètres). <em>getToken()</em> doit être, en quelque sorte, le miroir de <em>getPlace()</em>.</li>
</ul>
<h4>EditActivity :</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.greenivory.gwt.tutorial.client</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.activity.shared.Activity</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.event.shared.EventBus</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.user.client.ui.AcceptsOneWidget</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.gwt.user.client.ui.HTML</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> EditActivity <span style="color: #000000; font-weight: bold;">implements</span> Activity <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> EditPlace place<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #008000; font-style: italic; font-weight: bold;">/**
	 * @param place
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> EditActivity<span style="color: #009900;">&#40;</span>EditPlace place<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">place</span> <span style="color: #339933;">=</span> place<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> mayStop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Retourner null pour autoriser l'arrêt de l'Activity.</span>
		<span style="color: #666666; font-style: italic;">// Retourner une chaîne non-nulle pour demander à l'utilisateur si l'Activity doit être stoppée ou non.</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onCancel()
	 */</span>
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Exécutée quand l'Activity n'est pas démarrée.</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#onStop()
	 */</span>
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onStop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Exécutée quand l'Activity est arrêtée.</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* (non-Javadoc)
	 * @see com.google.gwt.activity.shared.Activity#start(com.google.gwt.user.client.ui.AcceptsOneWidget, com.google.gwt.event.shared.EventBus)
	 */</span>
	@Override
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> start<span style="color: #009900;">&#40;</span>AcceptsOneWidget panel, EventBus eventBus<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Code de l'Activity.</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>place.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			panel.<span style="color: #006633;">setWidget</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">HTML</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;&lt;strong&gt;Paramètre incorrect dans l'URL.&lt;/strong&gt;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
			panel.<span style="color: #006633;">setWidget</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">HTML</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Edition de l'élement &quot;</span> <span style="color: #339933;">+</span> place.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ce qu&#8217;il est important de retenir ici :</p>
<ul>
<li>Il est intéressant d&#8217;avoir accès à la Place pour en récupérer des informations (paramètres issus du token dans l&#8217;URL).</li>
</ul>
<p>Une fois que tout est en place, <strong>changer de vue est un véritable jeu d&#8217;enfant</strong> ! Il y a deux possibilités :</p>
<ol>
<li><strong>Dans un lien hypertexte</strong>, mettre l&#8217;URL de la Place vers laquelle on souhaite aller (attention au double-point derrière l&#8217;ancre, obligatoire, et souvent source de perte de temps).<br />
Par exemple <em>#list:</em> pour se rendre sur la liste des éléments.<br />
Ou <em>#edit:3</em> pour se rendre sur la <em>EditPlace</em> pour éditer l&#8217;élément qui a l&#8217;ID 3.</li>
<li><strong>Dans du code GWT</strong> avec (par exemple) :<br />
<em>ClientFactory.INSTANCE.getPlaceController().goTo(new EditPlace(47));</em></li>
</ol>
<p>Dans un prochain article, nous étudierons comment utiliser le pattern <strong>MVP</strong> pour construire des UI propres et éviter de faire des vues à rallonge&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.greenivory.fr/2011/10/21/gwt-activity-place-navigation-applications-web/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mise à jour de Safari (5) et GWT</title>
		<link>http://blog.greenivory.fr/2010/06/10/mise-a-jour-de-safari-5-et-gwt/</link>
		<comments>http://blog.greenivory.fr/2010/06/10/mise-a-jour-de-safari-5-et-gwt/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 07:15:21 +0000</pubDate>
		<dc:creator>Frédéric</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[mise à jour]]></category>
		<category><![CDATA[Safari]]></category>

		<guid isPermaLink="false">http://blog.greenivory.fr/?p=1048</guid>
		<description><![CDATA[J&#8217;ai mis à jour Safari 5 (car quelques nouveautés intéressantes) et je n&#8217;ai remarqué aucun souci avec le plugin GWT, ça passe ! J&#8217;suis pas non plus complètement fou, je m&#8217;étais renseigné, et ce qu&#8217;il ressortait c&#8217;est que ça passe quand on est sous Mac OS X 10.6 et que Safari tourne en 64 bits. [...]]]></description>
			<content:encoded><![CDATA[<div style="height:33px;" class="really_simple_share robots-nocontent snap_nopreview"><div class="really_simple_share_facebook_like" style="width:100px;">
				<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fblog.greenivory.fr%2F2010%2F06%2F10%2Fmise-a-jour-de-safari-5-et-gwt%2F&amp;layout=button_count&amp;show_faces=false&amp;width=100&amp;action=like&amp;colorscheme=light&amp;send=false&amp;height=27" 
						scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:27px;" allowTransparency="true"></iframe>
				</div><div class="really_simple_share_google1" style="width:90px;">
					<g:plusone size="medium" href="http://blog.greenivory.fr/2010/06/10/mise-a-jour-de-safari-5-et-gwt/" ></g:plusone>
				</div><div class="really_simple_share_twitter" style="width:110px;">
					<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" 
						data-text="Mise à jour de Safari (5) et GWT" data-url="http://blog.greenivory.fr/2010/06/10/mise-a-jour-de-safari-5-et-gwt/" 
						data-via="" ></a> 
				</div></div>
		<div style="clear:both;"></div><div>
<p>J&#8217;ai mis à jour <strong>Safari 5</strong> (car q<a href="http://www.apple.com/safari/whats-new.html#reader">uelques nouveautés intéressantes</a>) et je n&#8217;ai remarqué <strong>aucun souci avec le plugin GWT</strong>, ça passe !</p>
<p>J&#8217;suis pas non plus complètement fou, je m&#8217;étais renseigné, et ce qu&#8217;il ressortait c&#8217;est que ça passe quand on est sous Mac OS X 10.6 et que Safari tourne en 64 bits. Si vous n&#8217;êtes pas dans cette configuration-là, je ne vous conseille pas la mise à jour de Safari.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.greenivory.fr/2010/06/10/mise-a-jour-de-safari-5-et-gwt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tester son application GWT/GXT avec Selenium</title>
		<link>http://blog.greenivory.fr/2009/09/28/tester-son-application-gwtgxt-avec-selenium/</link>
		<comments>http://blog.greenivory.fr/2009/09/28/tester-son-application-gwtgxt-avec-selenium/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 10:45:11 +0000</pubDate>
		<dc:creator>Frédéric</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[GXT]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[test]]></category>

		<guid isPermaLink="false">http://blog.greenivory.fr/?p=545</guid>
		<description><![CDATA[GXT (grâce à GWT) permet de créer des applications web riches, dont l&#8217;ergonomie est assez proche d&#8217;une application lourde. Nous avons déjà eu l&#8217;occasion de publier des articles à ce sujet sur ce blog. Il est assez simple de faire des tests unitaires sur des services dans les couches basses d&#8217;une application. Et encore, dès [...]]]></description>
			<content:encoded><![CDATA[<div style="height:33px;" class="really_simple_share robots-nocontent snap_nopreview"><div class="really_simple_share_facebook_like" style="width:100px;">
				<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fblog.greenivory.fr%2F2009%2F09%2F28%2Ftester-son-application-gwtgxt-avec-selenium%2F&amp;layout=button_count&amp;show_faces=false&amp;width=100&amp;action=like&amp;colorscheme=light&amp;send=false&amp;height=27" 
						scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:27px;" allowTransparency="true"></iframe>
				</div><div class="really_simple_share_google1" style="width:90px;">
					<g:plusone size="medium" href="http://blog.greenivory.fr/2009/09/28/tester-son-application-gwtgxt-avec-selenium/" ></g:plusone>
				</div><div class="really_simple_share_twitter" style="width:110px;">
					<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" 
						data-text="Tester son application GWT/GXT avec Selenium" data-url="http://blog.greenivory.fr/2009/09/28/tester-son-application-gwtgxt-avec-selenium/" 
						data-via="" ></a> 
				</div></div>
		<div style="clear:both;"></div><p>GXT (grâce à GWT) permet de créer des <strong>applications web riches</strong>, dont l&#8217;ergonomie est assez proche d&#8217;une application lourde. Nous avons déjà eu l&#8217;occasion de publier des articles à ce sujet sur ce blog. Il est assez simple de faire des <strong>tests unitaires</strong> sur des services dans les couches basses d&#8217;une application. Et encore, dès qu&#8217;il y a une base de données en jeu, ça se complique (et c&#8217;est d&#8217;ailleurs très souvent le cas). Mais qu&#8217;en est-il des interfaces graphiques ? Evidemment, certains éléments graphiques peuvent être testés via des tests unitaires, mais comment s&#8217;assurer que l&#8217;interface, dans son ensemble, répond aux besoins ?</p>
<p>C&#8217;est là qu&#8217;intervient <a href="http://seleniumhq.org/">Selenium</a>. Selenium est un jeu d&#8217;outils qui permettent d&#8217;<strong>automatiser les tests d&#8217;interface graphique</strong>, en pilotant un navigateur via du code (ce code, c&#8217;est le <strong>testcase</strong>). Par exemple, on va pouvoir demander le chargement d&#8217;une page, effectuer un clic sur un lien bien précis, vérifier que la page contient un texte, &#8230; Une session complète sera dédiée à Selenium au <a href="http://developerforum.eu/">DeveloperForum 5</a>, le <strong>8 octobre 2009 à Strasbourg</strong>.</p>
<p>Mais avant de pouvoir tester nos interfaces, il faut mettre en place Selenium. Voici comment faire fonctionner Selenium dans un projet GWT dans Eclipse sur Mac OS X Snow Leopard (10.6).</p>
<h2>Comment ça marche ?</h2>
<p>Il faut deux éléments pour faire fonctionner le tout :</p>
<ul>
<li><strong>Selenium IDE</strong> est une extension Firefox qui permet d&#8217;enregistrer les actions réalisées dans la fenêtre de Firefox et d&#8217;ainsi produire le code du testcase (dans le langage de votre choix &#8211; dans notre cas, ce sera Java).</li>
<li><strong>Selenium RC</strong> (Remote Control) est un serveur capable de piloter un navigateur et pouvant recevoir des commandes via le réseau, déclenchées par le testcase.</li>
</ul>
<h2>Mise en place</h2>
<p>Utilisez Firefox pour télécharger et installer Selenium IDE (extension Firefox) : <a href="http://seleniumhq.org/download/">http://seleniumhq.org/download/</a><br />
Téléchargez ensuite Selenium RC et décompresser l&#8217;archive dans le répertoire de votre choix. Depuis ce répertoire, lancez Selenium RC via la ligne de commande :</p>
<pre>java -jar selenium-server-1.0.1/selenium-server.jar</pre>
<p>Le serveur se lance et devrait vous afficher les gentillesses suivantes :</p>
<pre>10:53:44.369 INFO - Java: Apple Inc. 14.1-b02-90
10:53:44.370 INFO - OS: Mac OS X 10.6.1 i386
10:53:44.379 INFO - v1.0.1 [2696], with Core v@VERSION@ [@REVISION@]
10:53:44.461 INFO - Version Jetty/5.1.x
10:53:44.462 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
10:53:44.463 INFO - Started HttpContext[/selenium-server,/selenium-server]
10:53:44.463 INFO - Started HttpContext[/,/]
10:53:44.475 INFO - Started SocketListener on 0.0.0.0:4444
10:53:44.475 INFO - Started org.mortbay.jetty.Server@1ff7a1e</pre>
<h2>Premier test</h2>
<p><strong>Dans Firefox</strong>, allez sur une page web de votre choix puis, dans le menu <em>Outils</em>, choisissez <em>Selenium IDE</em>. Commencez à surfer sur la page web et regardez Selenium &laquo;&nbsp;Big Brother&nbsp;&raquo; IDE enregistrer toutes vos actions dans le navigateur&#8230; Exactement comme lorsqu&#8217;on enregistre un macro dans certains logiciels. Après avoir navigué dans quelques pages, sélectionnez du texte dans la page et faites un clic droit puis sélectionnez l&#8217;option <em>verifyTextPresent &lt;le texte que vous avez sélectionné&gt;</em>.</p>
<p>Dans le menu de la <strong>fenêtre de Selenium</strong>, choisissez <em>Exporter le test sous&#8230;</em> puis choisissez <em>Java (JUnit)</em>. Enregistrez le fichier avec le nom de votre choix, sans oublier l&#8217;extension <em>.java</em>.</p>
<p><strong>Dans Eclipse</strong>, dans votre projet GWT/GXT, créez un nouveau dossier de sources nommé <em>test</em> (si ce n&#8217;est pas déjà fait). Ajoutez-y le fichier généré par Selenium IDE puis corrigez le nom du package ainsi que le nom de la classe. Corrigez le build path de votre projet en ajoutant le JAR <em>selenium-java-client-driver.jar</em> (que vous trouverez dans l&#8217;archive de Selenium que vous avez téléchargée). Clic droit sur la classe dans Eclipse puis <em>Run As &gt; JUnit Test</em>.</p>
<p>Et là, c&#8217;est le drame : une <strong>erreur se produit lors du lancement de Firefox</strong>. Après le passage à Snow Leopard, une incompatibilité de librairie est arrivée. Pour la contourner, il existe une <a href="http://stackoverflow.com/questions/1364523/firefox-bin-quit-unexpectedly-while-running-selenium-test">solution</a> qui vaut ce qu&#8217;elle vaut (j&#8217;adore cette expression qui ne veut rien dire dans l&#8217;absolu et qui pourtant veut bien dire&#8230; ce qu&#8217;elle veut dire !) :</p>
<ul>
<li>Quittez Firefox</li>
<li>Lancer le Terminal puis rendez-vous dans <em>/Applications/Firefox.app/Contents/MacOS</em>.</li>
<li>Renommez <em>libsqlite3.dylib</em> : <code>mv libsqlite3.dylib _libsqlite3.dylib</code></li>
</ul>
<p>Relancez votre testcase et tout devrait rentrer dans l&#8217;ordre !</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.greenivory.fr/2009/09/28/tester-son-application-gwtgxt-avec-selenium/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>GWT et les NullPointerException</title>
		<link>http://blog.greenivory.fr/2009/04/01/gwt-et-les-nullpointerexception/</link>
		<comments>http://blog.greenivory.fr/2009/04/01/gwt-et-les-nullpointerexception/#comments</comments>
		<pubDate>Wed, 01 Apr 2009 16:11:23 +0000</pubDate>
		<dc:creator>Frédéric</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[exception]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[null]]></category>

		<guid isPermaLink="false">http://blog.greenivory.fr/?p=221</guid>
		<description><![CDATA[Quelle histoire, ce sabotage de Google ! Un peu de sérieux, en attendant des nouvelles de ce cher Serge-Jean (plus facile à écrire qu&#8217;à dire !). Je me suis fait avoir par quelque chose d&#8217;assez subtil avec GWT. En parsant du XML avec le XMLParser fourni par GWT, j&#8217;ai eu besoin de récupérer la valeur d&#8217;attributs [...]]]></description>
			<content:encoded><![CDATA[<div style="height:33px;" class="really_simple_share robots-nocontent snap_nopreview"><div class="really_simple_share_facebook_like" style="width:100px;">
				<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fblog.greenivory.fr%2F2009%2F04%2F01%2Fgwt-et-les-nullpointerexception%2F&amp;layout=button_count&amp;show_faces=false&amp;width=100&amp;action=like&amp;colorscheme=light&amp;send=false&amp;height=27" 
						scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:27px;" allowTransparency="true"></iframe>
				</div><div class="really_simple_share_google1" style="width:90px;">
					<g:plusone size="medium" href="http://blog.greenivory.fr/2009/04/01/gwt-et-les-nullpointerexception/" ></g:plusone>
				</div><div class="really_simple_share_twitter" style="width:110px;">
					<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" 
						data-text="GWT et les NullPointerException" data-url="http://blog.greenivory.fr/2009/04/01/gwt-et-les-nullpointerexception/" 
						data-via="" ></a> 
				</div></div>
		<div style="clear:both;"></div><p>Quelle histoire, ce <a href="http://blog.greenivory.fr/2009/04/01/google-menace/">sabotage de Google</a> ! Un peu de sérieux, en attendant des nouvelles de ce cher Serge-Jean (plus facile à écrire qu&#8217;à dire !).</p>
<p>Je me suis fait avoir par quelque chose d&#8217;assez subtil avec GWT. En parsant du XML avec le <code>XMLParser</code> fourni par GWT, j&#8217;ai eu besoin de récupérer la valeur d&#8217;attributs optionnels. J&#8217;avais donc écrit des blocs de code qui ressemblent à peu près à ceci :</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">NamedNodeMap paramAttrs <span style="color: #339933;">=</span> paramNode.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">String</span> view <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
   view <span style="color: #339933;">=</span> paramAttrs.<span style="color: #006633;">getNamedItem</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;view&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getNodeValue</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">NullPointerException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span></pre></div></div>

<p>En me disant que si un élément est <code>null</code> dans la chaîne d&#8217;exécution, alors <code>view</code> vaudrait tout simplement <code>null</code>. Ceci est valable en Java, mais une fois traduit en JavaScript par GWT, ça ne marche pas du tout. La solution est donc de tester &laquo;&nbsp;à la main&nbsp;&raquo; les valeurs nulles :</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">NamedNodeMap paramAttrs <span style="color: #339933;">=</span> paramNode.<span style="color: #006633;">getAttributes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Node item <span style="color: #339933;">=</span> paramAttrs.<span style="color: #006633;">getNamedItem</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;view&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">String</span> view <span style="color: #339933;">=</span> item <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">?</span> item.<span style="color: #006633;">getNodeValue</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span></pre></div></div>

<p>Dans cet exemple, je vous l&#8217;accorde, ce n&#8217;est pas plus long et c&#8217;est même plus propre, mais j&#8217;avais un peu plus d&#8217;éléments dans ma ligne, et donc plusieurs valeurs (potentiellement nulles) à tester.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.greenivory.fr/2009/04/01/gwt-et-les-nullpointerexception/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scrollbar et RowLayout</title>
		<link>http://blog.greenivory.fr/2009/03/05/scrollbar-et-rowlayout/</link>
		<comments>http://blog.greenivory.fr/2009/03/05/scrollbar-et-rowlayout/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 12:02:21 +0000</pubDate>
		<dc:creator>Frédéric</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[GXT]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[scroll]]></category>

		<guid isPermaLink="false">http://blog.greenivory.fr/?p=82</guid>
		<description><![CDATA[L&#8217;utilisation d&#8217;un RowLayout dans un conteneur supprime la possibilité d&#8217;avoir une barre de défilement pour ce conteneur. En fait, la raison est assez simple : RowLayout calcule la position et la taille précises de chaque enfant, et c&#8217;est à chacun de ses enfants de gérer sa barre de défilement, au besoin. Donc, si vous avez [...]]]></description>
			<content:encoded><![CDATA[<div style="height:33px;" class="really_simple_share robots-nocontent snap_nopreview"><div class="really_simple_share_facebook_like" style="width:100px;">
				<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fblog.greenivory.fr%2F2009%2F03%2F05%2Fscrollbar-et-rowlayout%2F&amp;layout=button_count&amp;show_faces=false&amp;width=100&amp;action=like&amp;colorscheme=light&amp;send=false&amp;height=27" 
						scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:27px;" allowTransparency="true"></iframe>
				</div><div class="really_simple_share_google1" style="width:90px;">
					<g:plusone size="medium" href="http://blog.greenivory.fr/2009/03/05/scrollbar-et-rowlayout/" ></g:plusone>
				</div><div class="really_simple_share_twitter" style="width:110px;">
					<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" 
						data-text="Scrollbar et RowLayout" data-url="http://blog.greenivory.fr/2009/03/05/scrollbar-et-rowlayout/" 
						data-via="" ></a> 
				</div></div>
		<div style="clear:both;"></div><p>L&#8217;utilisation d&#8217;un <code>RowLayout</code> dans un conteneur supprime la possibilité d&#8217;avoir une barre de défilement pour ce conteneur. En fait, la raison est assez simple : <code>RowLayout</code> calcule la position et la taille précises de chaque enfant, et c&#8217;est à chacun de ses enfants de gérer sa barre de défilement, au besoin.</p>
<p>Donc, <strong>si vous avez besoin d&#8217;une barre de défilement dans un panneau, n&#8217;utilisez pas </strong><code><strong>RowLayout</strong></code> : dans la plupart des cas, un <code>FlowLayout</code> peut être préférable. Utiliser un <code>FlowLayout</code> revient à utiliser un <code>RowLayout(Orientation.VERTICAL)</code> avec des contraintes <code>RowData(1, -1)</code> pour chaque enfant (c&#8217;est-à-dire : utiliser toute la largeur disponible et laisser chacun des enfants calculer sa propre hauteur).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.greenivory.fr/2009/03/05/scrollbar-et-rowlayout/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Savoir si l&#8217;on est en mode &#171;&#160;hosted&#160;&#187; ou en mode &#171;&#160;web&#160;&#187;</title>
		<link>http://blog.greenivory.fr/2009/02/27/savoir-si-lon-est-en-mode-hosted-ou-en-mode-web/</link>
		<comments>http://blog.greenivory.fr/2009/02/27/savoir-si-lon-est-en-mode-hosted-ou-en-mode-web/#comments</comments>
		<pubDate>Fri, 27 Feb 2009 14:14:18 +0000</pubDate>
		<dc:creator>Frédéric</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[hosted mode]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[web mode]]></category>

		<guid isPermaLink="false">http://blog.greenivory.fr/?p=10</guid>
		<description><![CDATA[Il peut parfois être utile de savoir si l&#8217;on est en mode hosted ou en mode web dans une application GWT. En fait, cela m&#8217;est surtout utile pour faire des tests : en mode hosted (en cours de développement), j&#8217;attaque ma servlet de test et en mode web (déployé, donc), j&#8217;attaque la servlet réelle de [...]]]></description>
			<content:encoded><![CDATA[<div style="height:33px;" class="really_simple_share robots-nocontent snap_nopreview"><div class="really_simple_share_facebook_like" style="width:100px;">
				<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fblog.greenivory.fr%2F2009%2F02%2F27%2Fsavoir-si-lon-est-en-mode-hosted-ou-en-mode-web%2F&amp;layout=button_count&amp;show_faces=false&amp;width=100&amp;action=like&amp;colorscheme=light&amp;send=false&amp;height=27" 
						scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:27px;" allowTransparency="true"></iframe>
				</div><div class="really_simple_share_google1" style="width:90px;">
					<g:plusone size="medium" href="http://blog.greenivory.fr/2009/02/27/savoir-si-lon-est-en-mode-hosted-ou-en-mode-web/" ></g:plusone>
				</div><div class="really_simple_share_twitter" style="width:110px;">
					<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" 
						data-text="Savoir si l&#8217;on est en mode &laquo;&nbsp;hosted&nbsp;&raquo; ou en mode &laquo;&nbsp;web&nbsp;&raquo;" data-url="http://blog.greenivory.fr/2009/02/27/savoir-si-lon-est-en-mode-hosted-ou-en-mode-web/" 
						data-via="" ></a> 
				</div></div>
		<div style="clear:both;"></div><p>Il peut parfois être utile de savoir si l&#8217;on est en mode <em>hosted</em> ou en mode <em>web</em> dans une application GWT. En fait, cela m&#8217;est surtout utile pour faire des tests : en mode hosted (en cours de développement), j&#8217;attaque ma servlet de test et en mode web (déployé, donc), j&#8217;attaque la servlet réelle de l&#8217;application.</p>
<p>Pour cela, il faut utiliser la méthode statique <code>isScript()</code> de la classe <code>GWT</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> GWT.<span style="color: #006633;">isScript</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #666666; font-style: italic;">// Fonctionnement en mode web (déployé)</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://blog.greenivory.fr/2009/02/27/savoir-si-lon-est-en-mode-hosted-ou-en-mode-web/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

