sabato 15 novembre 2014

Primefaces combo con immagine

Primefaces (sto utilizzando la versione 3.5, ma la sintassi da utilizzare è la stessa nella  attuale 5.1)  consente agevolmente l'utilizzo di componenti web complessi, come ad esempio una combo in cui associamo una immagine per ogni elemento (esempio tipico per la scelta della lingua con la bandiera corrispondente).
Di seguito il codice utilizzato, prendendo spunto dallo showcase di PF.

POJO PER RAPPRESENTARE L'ELEMENTO DELLA COMBO


package it.test.managedBeans;

import java.io.Serializable;

public class Language implements Serializable {
 
 private static final long serialVersionUID = 442345384294917624L;
 private String code;
 private String descr;
 private String urlPath;
 
 public int hashCode() {
     return this.code.hashCode()+this.descr.hashCode()+this.urlPath.hashCode();
   }
 
 public boolean equals(Object o){
  if(o instanceof Language && o!=null) {
   Language l=(Language)o;
   
   if(l.getCode()!=null && l.getDescr()!=null 
&& l.getUrlPath()!=null && l.getCode().equals(this.code) && l.getDescr().equals(this.descr) 
&& l.getUrlPath().equals(this.urlPath)){
    return true;
   }
   else
   {
    return false;
   }
  }
  else
  {
   return false;
  }
 }
 public Language(){
  
 }
 public Language(String code,String descr,String urlPath){
  this.code=code;
  this.descr=descr;
  this.urlPath=urlPath;
 }
 public String getCode() {
  return code;
 }
 public void setCode(String code) {
  this.code = code;
 }
 public String getDescr() {
  return descr;
 }
 public void setDescr(String descr) {
  this.descr = descr;
 }
 public String getUrlPath() {
  return urlPath;
 }
 public void setUrlPath(String urlPath) {
  this.urlPath = urlPath;
 }
 
}


MANAGED BEAN

package it.test.managedBeans;
import it.dao.LanguageRetrievalDao;
import it.daoImpl.LanguageRetrievalDaoImpl;
import it.object.Language;
import it.util.Utility;
import java.util.List;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
@ManagedBean(name="languageLoader")
@SessionScoped
public class LanguageLoader {
 
 private  String locale = Locale.getDefault().getDisplayLanguage();

    public void setLocale(String locale1) {
      this.locale = locale1;
    }

    public synchronized String getLocale() {
      return locale;
    }
 
  private List listaLingue;
 
  private Language linguaSelezionata=null;
  @PostConstruct
     public void init() {
   try
   {
    
    LanguageRetrievalDao ldao=LanguageRetrievalDaoImpl.getInstance();
    this.listaLingue=ldao.getListaLinguaggi();
    Language loc=ldao.getLanguageByCode("it");
    this.locale=loc.getCode();
   this.linguaSelezionata=loc;
   }
   catch(Exception ex){
    Utility.aggiungiMessaggioErrore(ex.getMessage());
   }
  }

 public List getListaLingue() {
  return listaLingue;
 }

 public void setListaLingue(List listaLingue) {
  this.listaLingue = listaLingue;
 }

 public Language getLinguaSelezionata() {
  return linguaSelezionata;
 }

 public void setLinguaSelezionata(Language linguaSelezionata) {
  this.linguaSelezionata = linguaSelezionata;
 }
  

  
 public void prova(ActionEvent ev){
   
  Utility.aggiungiMessaggioInformativo("E' stato selezionato il valore "+this.linguaSelezionata.getDescr());
  this.setLocale(this.linguaSelezionata.getCode());
 
 }
 
 public void prova3(){
   
  Utility.aggiungiMessaggioInformativo("E' stato selezionato il valore "+this.linguaSelezionata.getDescr());
  this.setLocale(this.linguaSelezionata.getCode());
  Locale.setDefault(new Locale(this.linguaSelezionata.getCode()));
 
 }
}



I due metodi prova e prova3 sono invocati il primo ad un onchange della combo, l'altro invece è un metodo invocato da un actionlistener.

ESEMPIO XHTML CON EVENTO CHE SCATTA ALL'ONCHANGE


<html xmlns="http://www.w3c.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"  xmlns:f="http://java.sun.com/jsf/core" 
xmlns:ui="http://java.sun.com/jsf/facelets"   xmlns:p="http://primefaces.org/ui"  xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<f:view contentType="text/html" locale="#{languageLoader.locale}">
<h:head >
</h:head>
<h:body> 
<h:form id="mainForm">
<br/>
<br/>
<br/>
 <p:growl id="msgs" showDetail="true"  />
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<p:selectOneMenu value="#{languageLoader.linguaSelezionata}"  var="immagine">
<f:converter converterId="myComboLanguageConverter"></f:converter>
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{languageLoader.listaLingue}" var="lingua"
itemLabel="#{lingua.descr}" itemValue="#{lingua}"/>
<p:ajax event="change" update="msgs"  
                            listener="#{languageLoader.prova3}" /> 
<p:column>
<p:graphicImage value="/images/lang/#{immagine.urlPath}" width="40" height="50"/>
</p:column>
<p:column>
#{immagine.code} - #{immagine.descr}
</p:column>
</p:selectOneMenu>
</h:form>
 </h:body>
 </f:view>
</html>


ESEMPIO XHTML CON EVENTO SCATENATO DA PRESSIONE DI BOTTONE


<html xmlns="http://www.w3c.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"  xmlns:f="http://java.sun.com/jsf/core" 
xmlns:ui="http://java.sun.com/jsf/facelets"   xmlns:p="http://primefaces.org/ui"  xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<f:view contentType="text/html" locale="#{languageLoader.locale}">
<h:head >
</h:head>
<h:body> 
<h:form id="mainForm">
<br/>
<br/>
<br/>
 <p:growl id="msgs" showDetail="true"  />
<br/>
<br/>
<p:selectOneMenu value="#{languageLoader.linguaSelezionata}" id="combo1"  var="immagine">
<f:converter converterId="myComboLanguageConverter"></f:converter>
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{languageLoader.listaLingue}" var="lingua"
itemLabel="#{lingua.descr}" itemValue="#{lingua}"/>
<p:column>
<p:graphicImage value="/images/lang/#{immagine.urlPath}" width="40" height="50"/>
</p:column>
<p:column>
#{immagine.code} - #{immagine.descr}
</p:column>
</p:selectOneMenu>
<br/>
<p:commandButton actionListener="#{languageLoader.prova}" value="TEST"  update="msgs combo1"></p:commandButton>
<br/>
<br/>
<br/>
</h:form>
 </h:body>
 </f:view>
</html>


CONVERTER

Si noti che il converter si utilizza per trasformare l'oggetto in stringa e viceversa e non entra in gioco nella rappresentazione della combo stessa con le immagini ma negli eventi successivi al click del pulsante oppure al cambiamento della combo stessa.

package it.test.managedBeans;
import it.dao.LanguageRetrievalDao;
import it.daoImpl.LanguageRetrievalDaoImpl;
import it.object.Language;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
@FacesConverter("myComboLanguageConverter")
public class LanguageConverter implements Converter {

 @Override
 public Object getAsObject(FacesContext context, UIComponent
   component, String value) {
  LanguageRetrievalDao lr=LanguageRetrievalDaoImpl.getInstance();
  return lr.getLanguageByCode(value);
 }

 @Override
 public String getAsString(FacesContext context, UIComponent component, Object value) {
  if(value instanceof Language){
   return ((Language)value).getCode();
  }
  else
  {
   return "";
  }
  
 }

}



Attenzione è importantissimo nella selectOneMenu impostare l'itemValue direttamente con il valore dell'oggetto, non con il codice della lingua, infatti poi è il componente di primefaces che sfruttando i metodi equals ed hascode dell'oggetto Language associa correttamente immagini e descrizioni al codice dato ("it" oppure "en").