NO A LA LEY SOPA - EL CONOCIMIENTO ES Y DEBE SER LIBRE -

viernes, enero 06, 2012

MI PRIMER WEB SITE CON GWT ( PARA NOVATOS )

UIBinder sin GWT Designer era realmente horrible, la curva de aprendizaje era muy empinada, con GWT Designer la cosa cambia radicalmente y ahora estoy convencido que si es posible realizar páginas web con GWT.

UIBinder  es una herramienta poderosa  que te permite dividir pedazos de código HTML de tu “Plantilla CSS”  para después insertar estos pedazos de código dinámicamente a través de Javascript (GWT) en tu “Plantilla CSS”.  Si vienes de PHP la inserción de los pedazos de código lo realizas dinámicamente a través de PHP en el Servidor, si te has percatado es prácticamente la misma lógica de desarrollo con la diferencia que ahora trabajas en el Cliente.

Los programadores Javascript podrían argumentar que pueden realizar lo anteriormente mencionado sin necesidad de UIBinder ; sin embargo, no olviden que UIBinder es en esencia Java y además tienes la opción de visualizar el diseño con GWT Designer, además UIBinder  te permite separar el código de la IU (XML) del código de implementación (Java). Esto implica que puedes tener un UIBinder incrustado dentro de un UIBinder y en fin todo el poder de un lenguaje como Java (odio y maldigo el manejo de eventos de Java, amo C# no me digan hereje).


EJEMPLO:

Este ejemplo es bastante básico, hay temas de optimización y rendimiento como: ClientBunde, Code Split entre otros  que intencionalmente no se muestran aquí.

  1.  Tenemos la plantilla inicial.
    Codigo: Index.html
    <div id="header" class="container">
     <div id="logo">
      <h1><a href="#">Rock Castle</a></h1>
     </div>
    
     <!-- Begin Menu -->
    
        <div id="menu">
    
      <ul>
    
       <li class="current_page_item"><a href="#">Homepage</a></li>
       <li><a href="#">Blog</a></li>
       <li><a href="#">Photos</a></li>
       <li><a href="#">About</a></li>
       <li><a href="#">Contact</a></li>
    
      </ul>
    
     </div>
    
        <!-- End Menu -->
    
    </div>
    
    <div id="splash-wrapper">
    
     <div id="splash">
    
      <h2>Nullam pretium nibh u turpis</h2>
    
      <p>Lorem ipsum daolor sit amet, consectetur adipiscing elit. Nulla quis orci ut erat iaculis posuere in consequat nulla. Cras vel nisl ipsum, nec tincidunt nunc. Sed egestas lorem nisl, sed dignissim quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce tristique dui sit amet mauris.</p>
    
     </div>
    
    </div>
    
    <!-- end #header -->
    
    <div id="wrapper">
    
     <div id="wrapper2">
    
      <div id="wrapper-bgtop">
    
       <div id="page">
    
        <div id="content">
    
                    
    
         <!-- Beging Post -->
    
                        <div class="post">
    
          <h2 class="title"><a href="#">Welcome to Rock Castle</a></h2>
    
          <p class="meta"><span class="date">December 12, 2011</span><span class="posted">Posted by <a href="#">Someone</a></span></p>
    
          <div style="clear: both;"> </div>
    
          <div class="entry">
    
           <p>This is <strong>Rock Castle</strong>, a free, fully standards-compliant CSS template designed by FreeCssTemplates<a href="http://www.nodethirtythree.com/"></a> for <a href="http://www.freecsstemplates.org/">Free CSS Templates</a>.  This free template is released under a <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a> license, so you’re pretty much free to do whatever you want with it (even use it commercially) provided you keep the links in the footer intact. Aside from that, have fun with it :)</p>
    
           <p>Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum ipsum. Proin imperdiet est. Phasellus dapibus semper urna. Pellentesque ornare, orci in felis. Donec ut . In id eros. Suspendisse  turpis, cursus egestas at sem.</p>
    
           <p class="links"><a href="#" class="more">Read More</a><a href="#" title="b0x" class="comments">Comments</a></p>
    
          </div>
    
         </div>
    
                        <!-- End Post -->
    
    
  2. Creamos un Widget “Menu” y un Widget “Post” como puede observar se ha copiado el código correspondiente de la plantilla a los Widgets esto es lo interesante; ya que, puede ejecutar el GWT Designer y visualizar el diseño  de cada Widget.
    Codigo: Menu.ui.xml
    <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
    
    <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    
     xmlns:g="urn:import:com.google.gwt.user.client.ui">
    
     <ui:style>
    
      
    
     </ui:style>
    
     <g:HTMLPanel>
    
     <div id="menu">
    
      <ul>
    
       <li><a href="#">Homepage</a></li>
       <li><a href="#">Blog</a></li>
       <li><a href="#">Photos</a></li>
       <li><a href="#">About</a></li>
       <li><a href="#">Contact</a></li>
    
      </ul>
    
     </div>
    
     </g:HTMLPanel>
    
    </ui:UiBinder> 
    
  3. En la Plantilla inicial ahora declaramos  elementos “div”  con los identificadores "wmenu" y "wpost", mediante GWT insertaremos dinámicamente los Widgets creados en los  elementos “div” a traves de los identificadores.
    Codigo: Index.html
    <div id="header" class="container">
    
     <div id="logo">
    
      <h1><a href="#">Rock Castle</a></h1>
    
     </div>
    
     <!-- Begin Menu -->
    
        <div id="wmenu"></div><!-- ACA INSERTAMOS EL WIDGET MENU -->
    
        <!-- End Menu -->
    
    </div>
    
    <div id="splash-wrapper">
    
     <div id="splash">
    
      <h2>Nullam pretium nibh u turpis</h2>
    
      <p>Lorem ipsum daolor sit amet, consectetur adipiscing elit. Nulla quis orci ut erat iaculis posuere in consequat nulla. Cras vel nisl ipsum, nec tincidunt nunc. Sed egestas lorem nisl, sed dignissim quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce tristique dui sit amet mauris.</p>
    
     </div>
    
    </div>
    
    <!-- end #header -->
    <div id="wrapper">
     <div id="wrapper2">
      <div id="wrapper-bgtop">
       <div id="page">
        <div id="content">
                    
    
         <!-- Beging Post -->
    
                        <div id="wpost"></div><!-- ACA INSERTAMOS EL WIDGET POST -->
    
                         <!-- End Post -->
    
  4. Ahora  cuando se haga click sobre cada elemento del Menu se insertara  el Widget “Post” haciendo referencia al elemento  “div” cuyo identificado es “wpost”.
    Codigo: Menu.java
    @UiHandler("labelHomepage")
     void onLabelHomepageClick(ClickEvent event) {
      RootPanel.get("wpost").clear();
     }
    
     @UiHandler("labelBlog")
     void onLabelBlogClick(ClickEvent event) {
      Post post=new Post();
      RootPanel.get("wpost").add(post);
     }
    
     @UiHandler("labelPhotos")
     void onLabelPhotosClick(ClickEvent event) {
      Post post=new Post();
      post.setWidgetPanel(new Formulario());
      RootPanel.get("wpost").add(post);
     }
    

Debo de mencionar que la mayoría del código del proyecto es generado automáticamente por GWT Designer, el ejemplo lo puede ver http://websitegwt.appspot.com/ y el código fuente de proyecto aquí.


martes, noviembre 29, 2011

UIBINDER EL PUENTE ENTRE GWT Y LOS DISEÑADORES WEB TRADICIONALES (HTML+CSS)

La mayoría de los mejores diseñadores web que conozco no tienen la lógica de un programador y esto es una traba  para engancharlos a GWT (aunque con HTML 5 necesariamente van a tener que aprender); sin embargo, con UIBInder veo la posibilidad de usar ese talento en beneficio de las Aplicaciones GWT.


PROBLEMA  1:
Como atraer  a ese mi Amigo, experto  en maquetación y diseño CSS,  al mundo de GWT sin que muera de  pánico?


SOLUCIÓN  1:
Copiar ese código bonito (html + csss) y pegarlo en UIBinder enseguida UIBinder lo transformara en un Widget y podremos utilizarlo  como si se tratase de un Widget Nativo, entonces insertar el Widget recién creado en una Layer, Grid, Panel, etc.


CONCLUSIÓN 1:
1)      Esto permite tomar trozos de código (html + css) y utilizarlo con GWT, entonces estos pedazos de códigos están elegantemente encapsulados en Widgets GWT.
2)      Aunque GW T ayuda desmesuradamente a realizar Aplicación Web, con UIBinder podrás construir Web Sites  sin necesidad de encontrarte con los fastidiosos refrescos totales de página que se originan después de realizar un requerimiento al Servidor y  además como para completar la historia subir tu Web Site a AppEngine.


PROBLEMA 2:
Como podemos implementar los eventos  JavaScript del código bonito de mi Amigo en el UIBinder ?


SOLUCIÓN 2:
1)      Podemos dejar los el código JavaScript tal cual dentro de UIBinder  y a través de JSNI (JavaScript Native Interface) utilizarlo en GWT.
2)       Eliminar todo el código Javascript y enseguida crear los eventos a través de los Widgets GWT


Ejemplo:


Código fuente Menu.ui.xml  (UIBINDER)
<div id="menuv">
        <ul>

         <li><a href="#menuv"><g:Label ui:field="menu1" text="Importante" /></a></li>
         <li><a href="#menuv">Comentarios</a></li>
         <li><a href="#menuv">Noticias</a></li>
         <li><a href="#menuv">Contacto</a></li>
         <li><a href="#menuv">Acerca de nosotros</a></li>
        </ul>
</div>

Código fuente Menu.java  (UIBINDER)

@UiField Label menu1; 
@UiHandler("menu1")
void onClick(ClickEvent e) {
  Window.alert("saludo");
}

Como puedes ver solo estamos insertando el < tag > del Widget Label en el “Menu.ui.xml”  después  en el “Menu.java”  podemos referenciar al < tag > creado  que es un Widget Label y crear los eventos asociados respectivos.

 Ahora el Widget “Menu” que se creó a partir de código HTML y CSS lo podemos agregar al Widget “HTMLPanel” y visualizar su funcionamiento tal como se muestra en el código de abajo.


Código fuente WEB.java
HTMLPanel panelIzquierdo = new HTMLPanel("");

.

.

.

Menu menu=new Menu(panelDerecho);

panelIzquierdo.add(menu);/* Insertamos el Widget Menu*/



CONCLUSIÓN 2:
1)      Con UIBinder separamos el diseño de la lógica de programación incrementando significativamente la Productividad.

Para una mejor comprensión del asunto te invito a ver el siguiente video – tutorial.



viernes, septiembre 30, 2011

PROGRAMITA (SMARTGWT LGPL + PHP)

Estuve buscando viejos programitas y encontré  un programita bastante sencillo cuyo objetivo era registrar la cantidad  de votos procesados para las elecciones municipales y así determinar ,antes que el Jurado  Nacional de Elecciones diera el resultado oficial,  si el candidato había ganado (En mi País todavía no hay voto electrónico ).
Muestro el  video para que vean la sencillez del asunto, mencionar que se construyó con SmartGWT LGPL + PHP + MYSQL.  Espero que este post sea el reinicio de mi etapa  bloguera.


domingo, diciembre 26, 2010

PRIMEROS PASOS CON: SMARTGWT LGPL+APP ENGINE

ACLAREMOS EL PANORAMA
SMARTGWT EE (Enterprise Edition) hace uso del protocolo GWT-RPC; por lo tanto,  el Servidor (contenedor de Servlets) debe entender Java.  Sin embargo, existe un proyecto denominado  GWTPPHP que intenta implementar GWT-RPC para usarlo con PHP (lamentablemente la actividad del proyecto es bastante baja, casi nula) .

SMARTGWT LGPL (FREE) puede recuperar los datos en formato JSON o XML vía HTTP (como se ha mostrado a lo largo de este Blog). Sin embargo, en el foro de SmartGWT encontraran una librería llamada GwtRpcDataSource (desarrollada por marbot)  que nos permite utilizar GWT-RPC, pero todavía no está lo bastante madura.

Debido a lo anteriormente mencionado en este post nos comunicaremos con Appengine a través de scripts jsp(java server page), es decir JSON vía HTTP.

Aunque he conseguido realizar  pequeños proyectos con SmartGWT  LGPL con PHP usando  MVP . Seguir con la misma filosofía  con un Servidor Java (contenedor de Servlets) es factible, aunque tendría que construir un framework MVP (similar al construido con PHP),  en el corto plazo no está en mis planes.

EL EJEMPLO
El ejemplo mostrado tiene el mismo funcionamiento de de la entrada: “PRIMEROS PASOS CON: GWT DESIGNER  + SMARTGWT + PHP”. Solo se ha migrado la aplicación, que inicialmente corría sobre el Servidor Web Apache, para que ahora se ejecute sobre el Almacén de Datos de Appengine.
En esta dirección podrás ver la ejecución del ejemplo:  http://gwtdesigner2010.appspot.com  , la librería SmartGwt es bastante pesada, así que, tendrás que tener un poco de paciencia.
La entrada “PRIMEROS PASOS CON: GWT DESIGNER  + SMARTGWT + PHP” genero un proyecto que lo llamamos “gwtdesigner” es conveniente que habrás este proyecto para completar el ejemplo; ya que, haremos uso del código ahí mostrado.

Los pasos que se muestran en el video-tutorial se pueden resumir como sigue:
  1. Creamos un nuevo proyecto nombrándolo como “gwtdesignerAppEngine“.
  2. Borramos el código generado, por el Asistente, convenientemente (ver el video).
  3. Copiamos “DSDesigner.java” y “gwtdesigner.java” del proyecto “gwtdesigner” a nuestro paquete “pck.client”.
  4. Modificamos  el archivo de configuración (gwt.xml) para que el punto de entrada (entry point) del proyecto sea “gwtdesigner.java”; ya que, el asistente creo  por defecto el “gwtdesignerappengine.java” como punto de entrada.
  5. Eliminamos “gwtdesignerappengine.java”.
  6. Creamos los archivo “add.jsp”,” remove.jsp” y “update.jsp”.
  7. Creamos el archivo “Empleados.java” y “PMF.java”, enseguida los añadimos en “pck.server”.
  8. Modificamos “DSDesigner.java” para que se direccionen a:  “add.jsp”,” remove.jsp” y “update.jsp”.
  9. Subimos la proyecto a AppEngine.   
Esta entrada se continuara actualizando… en el breve plazo.

/*
 * Codigo Fuente PMF.java
 */
package pck.server;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
    private static final PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

    private PMF() {}

    public static PersistenceManagerFactory get() {
        return pmfInstance;
    }
}
/*
 * Codigo Fuente Empleado.java
 */
package pck.server;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Empleado {
 
 @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
 @Persistent
 private String nombres;
 @Persistent
 private String dni;
 @Persistent
 private String email;
 
 public Empleado(String Nombres, String Dni,String Email) {
  this.nombres=Nombres;
        this.dni=Dni;
        this.email=Email;
    }

 public void setNombres(String nombres) {
  this.nombres = nombres;
 }

 public String getNombres() {
  return nombres;
 }

 public void setDni(String dni) {
  this.dni = dni;
 }

 public String getDni() {
  return dni;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public String getEmail() {
  return email;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public Long getId() {
  return id;
 }
}
<%
/*
* Codigo Fuente add.jsp
*/
%>
<%@ page import= "pck.server.*" %>
<%@ page import= "java.util.List" %>
<%@ page import= "javax.jdo.PersistenceManager" %>
<%@ page import= "com.google.appengine.repackaged.org.json.JSONArray" %>
<%@ page import= "com.google.appengine.repackaged.org.json.JSONObject" %>
<%
  String nombres=request.getParameter("nombres");
  String dni=request.getParameter("dni");
  String email=request.getParameter("email");
  
  Empleado employee = new Empleado(nombres, dni,email);
  PersistenceManager pm = PMF.get().getPersistenceManager();

  JSONObject enviar=new JSONObject();
  JSONObject resp=new JSONObject();
  JSONArray data=new JSONArray(); 

  try {   
    employee=pm.makePersistent(employee);
             
    JSONObject reg= new  JSONObject();
    reg.put("id", employee.getId());
    reg.put("nombres", nombres);
    reg.put("dni", dni);
    reg.put("email", email);
    data.put(0, new JSONObject(reg.toString()));
    pm.close();
   resp.put("status",0);
   resp.put("data",new JSONArray(data.toString())); 
   enviar.put("response", new JSONObject(resp.toString()));
   
  } catch (Exception e) {
   pm.close();
   response.setContentType("text/plain");
   response.getWriter().println(e.toString());
  }
  
  response.setContentType("text/plain");
  response.getWriter().println(enviar.toString());
%>
<%
/*
* Codigo Fuente fetch.jsp
*/
%>
<%@ page import= "pck.server.*" %>
<%@ page import= "java.util.List" %>
<%@ page import= "javax.jdo.PersistenceManager" %>
<%@ page import= "com.google.appengine.repackaged.org.json.JSONArray" %>
<%@ page import= "com.google.appengine.repackaged.org.json.JSONObject" %>

<%
  JSONObject enviar=new JSONObject();
  JSONObject resp=new JSONObject();
  JSONArray data=new JSONArray(); 
  
  PersistenceManager pm = PMF.get().getPersistenceManager();
   
  try {
   
   String query = "select from " + Empleado.class.getName();
   
      List<Empleado> employees = (List<Empleado>) pm.newQuery(query).execute();   
   
   for(int i=0;i<employees.size();i++){
    
    JSONObject reg= new  JSONObject();
    reg.put("id", employees.get(i).getId());
    reg.put("nombres", employees.get(i).getNombres());
    reg.put("dni", employees.get(i).getDni());
    reg.put("email", employees.get(i).getEmail());
    
    data.put(i, new JSONObject(reg.toString()));
   }
   pm.close();
   resp.put("status",0);
   resp.put("data",new JSONArray(data.toString())); 
   enviar.put("response", new JSONObject(resp.toString()));
   
  } catch (Exception e) {
   pm.close();
   response.setContentType("text/plain");
   response.getWriter().println(e.toString());
  }
  response.setContentType("text/plain");
  response.getWriter().println(enviar.toString());
  
%>
<%
/*
* Codigo Fuente update.jsp
*/
%><%@ page import= "pck.server.*" %>
<%@ page import= "java.util.List" %>
<%@ page import= "javax.jdo.PersistenceManager" %>
<%@ page import= "com.google.appengine.repackaged.org.json.JSONArray" %>
<%@ page import= "com.google.appengine.repackaged.org.json.JSONObject" %>

<%
  String id=request.getParameter("id");
  String nombres=request.getParameter("nombres");
  String dni=request.getParameter("dni");
  String email=request.getParameter("email");
  
  JSONObject enviar=new JSONObject();
  JSONObject resp=new JSONObject();
  JSONArray data=new JSONArray(); 
  
  PersistenceManager pm = PMF.get().getPersistenceManager();
    
  try {
    Empleado e = pm.getObjectById(Empleado.class, Long.parseLong(id));
    
    e.setDni(dni);
    e.setNombres(nombres);
    e.setEmail(email);
    
    pm.close();
    
    JSONObject reg= new  JSONObject();
    reg.put("id", Integer.parseInt(id));
    reg.put("nombres", nombres);
    reg.put("dni", dni);
    reg.put("email", email);
    data.put(0, new JSONObject(reg.toString()));
   
   resp.put("status",0);
   resp.put("data",new JSONArray(data.toString())); 
   enviar.put("response", new JSONObject(resp.toString()));
   
  } catch (Exception e) {
   
   pm.close();
   response.setContentType("text/plain");
   response.getWriter().println(e.toString());
  }
  response.setContentType("text/plain");
  response.getWriter().println(enviar.toString());
%>

martes, noviembre 02, 2010

PRIMEROS PASOS CON: GWT DESIGNER + SMARTGWT + PHP

GWT Designer todavía no soporta ampliamente a SmartGWT, como consecuencia de esto se siente desesperadamente lento el IDE (contrariamente a GWT que se siente más rápido).
Sin embargo, aun con sus carencias puede ayudar considerablemente en el Diseño de una Interfaz.

El ejemplo simplemente mostrara, añadirá y editara Empleados de una gran Empresa (encargada de construir un framework al estilo de Spring Roo), para conseguir con el objetivo haremos uso de”DynamicForm” una clase de SmartGwt que reducirá significativamente el código de las operaciones.

Hasta la línea 116 del código fuente (gwtDesigner.java) lo genera GWT Designer salvo la línea 49 y 116  que se añaden programáticamente “BeginGrid” y “Begin”, respectivamente. Teniendo en claro lo anterior proceda a realizar el ejemplo como se muestran en los videos-tutoriales sin olvidar las Variables Locales que deben ser convertidos en Atributos de la Clase.(dependiendo de su configuracion, por defecto GWT Designer crea los Widgets como Variables Locales)

Nota: Este ejemplo se ejecuta con: GWT 2.1, GWT Designer 8.1, SmartGWT 2.2 y  PHP 5.2.3




Qué realiza DynamicForm?
DynamicForm nos permite crear y editar un registro muy rápidamente, simplemente hay que asignarle un DataSource  al DynamicForm. DynamicForm automáticamente reconocerá los campos del DataSource asignado y se verán reflejados en un Formulario. En nuestro ejemplo creamos los Formularios “dynamicFormNuevo” y “dynamicFormEditar”
public void Begin(){
    ...
    dynamicFormNuevo.setDataSource(DSDesigner.getInstance());
    dynamicFormEditar.setDataSource(DSDesigner.getInstance());
   }
Cómo creamos un Empleado?
Antes de poder crear un Empleado será necesario validar el ingreso de datos. El método “saveData” de DynamicForm llamara automáticamente a “fetch.php”.
public void OnClickNuevo_Guardar(){
    if(dynamicFormNuevo.validate()){
     dynamicFormNuevo.saveData();
     ...
     ...
    }
   }
Cómo editamos un Empleado?
En nuestro ejemplo para poder editar un Empleado necesitamos implementar el evento “onRecordClick” de la grilla “listgrid”.
public void OnClickRecordGrid(){
    dynamicFormEditar.reset();
    dynamicFormEditar.editSelectedData(listGrid);
   }
Enseguida procedemos a validar el ingreso de datos con el método “validate”, después guardamos los cambios realizados con el método “saveData”que automáticamente llamara a “update.php”.
public void OnClickEditar_Guardar(){
    if(dynamicFormEditar.validate()){
     dynamicFormEditar.saveData();
     ...
     ...
    }
   }



/**
 * Codigo Fuente GWTDesigner
 */
public class gwtdesigner implements EntryPoint {
 private DynamicForm dynamicFormEditar;
 private Tab tabEditar;
 private Tab tabNuevo;
 private DynamicForm dynamicFormNuevo;
 private Tab tabGrilla;
 private ListGrid listGrid;
 private TabSet tabSet;
 
 public void onModuleLoad() {
  RootPanel rootPanel = RootPanel.get();
  
  tabSet = new TabSet();
  tabGrilla=new Tab("Empleados");
  
  VLayout layout = new VLayout();
  
  ToolStrip toolStrip = new ToolStrip();
  toolStrip.setSize("100%", "25px");
  
  ToolStripButton btnGrillaNuevo = new ToolStripButton("Nuevo");
  btnGrillaNuevo.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    OnClickGrilla_Nuevo();
   }
  });
  btnGrillaNuevo.setIcon("icons/16/new.gif");
  toolStrip.addButton(btnGrillaNuevo);
  
  ToolStripButton btnGrillaEditar = new ToolStripButton("Editar");
  btnGrillaEditar.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    OnClickGrilla_Editar();
   }
  });
  btnGrillaEditar.setIcon("icons/16/edit.png");
  toolStrip.addButton(btnGrillaEditar);
  layout.addMember(toolStrip);
  
  listGrid = new ListGrid();
  listGrid.addRecordClickHandler(new RecordClickHandler() {
   public void onRecordClick(RecordClickEvent event) {
    OnClickRecordGrid();
   }
  });
  BeginGrid();
  layout.addMember(listGrid);
  tabGrilla.setPane(layout);
  tabNuevo=new Tab("Nuevo");
  
  VLayout layout_1 = new VLayout();
  
  ToolStrip toolStrip_1 = new ToolStrip();
  toolStrip_1.setSize("100%", "25px");
  
  ToolStripButton btnNuevoGuardar = new ToolStripButton("Guardar");
  btnNuevoGuardar.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    OnClickNuevo_Guardar();
   }
  });
  btnNuevoGuardar.setIcon("icons/16/disk_blue.png");
  toolStrip_1.addButton(btnNuevoGuardar);
  
  ToolStripButton btnNuevoSalir = new ToolStripButton("Salir");
  btnNuevoSalir.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    OnClickNuevo_Salir();
   }
  });
  btnNuevoSalir.setIcon("icons/16/salir.png");
  toolStrip_1.addButton(btnNuevoSalir);
  layout_1.addMember(toolStrip_1);
  
  dynamicFormNuevo = new DynamicForm();
  layout_1.addMember(dynamicFormNuevo);
  tabNuevo.setPane(layout_1);
  tabEditar=new Tab("Editar");
  
  VLayout layout_2 = new VLayout();
  
  ToolStrip toolStrip_2 = new ToolStrip();
  toolStrip_2.setSize("100%", "25px");
  
  ToolStripButton btnEditarGuardar = new ToolStripButton("Guardar");
  btnEditarGuardar.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    OnClickEditar_Guardar();
   }
  });
  btnEditarGuardar.setIcon("icons/16/disk_blue.png");
  toolStrip_2.addButton(btnEditarGuardar);
  
  ToolStripButton btnEditarSalir = new ToolStripButton("Salir");
  btnEditarSalir.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    OnClickEditar_Salir();
   }
  });
  btnEditarSalir.setIcon("icons/16/salir.png");
  toolStrip_2.addButton(btnEditarSalir);
  layout_2.addMember(toolStrip_2);
  
  dynamicFormEditar = new DynamicForm();
  layout_2.addMember(dynamicFormEditar);
  tabEditar.setPane(layout_2);
  tabSet.addTab(tabGrilla);
  tabSet.addTab(tabNuevo);
  tabSet.addTab(tabEditar);
  tabSet.setSize("430px", "299px");
  rootPanel.add(tabSet, 10, 10);
  
  Begin();
 }
 /*
    * Inicio de Eventos
    */
   public void OnClickGrilla_Nuevo(){
    tabNuevo.setDisabled(false);
    tabSet.selectTab(1);
    dynamicFormNuevo.reset();
   }
   public void OnClickGrilla_Editar(){
    tabEditar.setDisabled(false);
    tabSet.selectTab(2);
   }
   public void OnClickNuevo_Guardar(){
    if(dynamicFormNuevo.validate()){
     dynamicFormNuevo.saveData();
     tabNuevo.setDisabled(true);
     tabSet.selectTab(0); 
    }
   }
   public void OnClickNuevo_Salir(){
    tabNuevo.setDisabled(true);
    tabSet.selectTab(0);
   }
   public void OnClickEditar_Guardar(){
    if(dynamicFormEditar.validate()){
     dynamicFormEditar.saveData();
     tabEditar.setDisabled(true);
     tabSet.selectTab(0);
    }
   }
   public void OnClickEditar_Salir(){
    tabEditar.setDisabled(true);
    tabSet.selectTab(0);
   }
   public void OnClickRecordGrid(){
    dynamicFormEditar.reset();
    dynamicFormEditar.editSelectedData(listGrid);
   }
   public void BeginGrid(){
       
    listGrid.setDataSource(DSDesigner.getInstance());
    //$hide>>$
    listGrid.setAutoFetchData(true);
    //$hide<<$
    ListGridField  id = new ListGridField ("id", "ID",20);
    ListGridField  nombres = new ListGridField ("nombres", "NOMBRES",100);
    ListGridField  dni = new ListGridField ("dni", "DNI",60);
    ListGridField  telefono = new ListGridField ("email", "E-MAIL");
    listGrid.setFields(id,nombres,dni,telefono);
   }
   public void Begin(){
    //$hide>>$
    tabNuevo.setDisabled(true);
    tabEditar.setDisabled(true);
    //$hide<<$
    dynamicFormNuevo.setDataSource(DSDesigner.getInstance());
    dynamicFormEditar.setDataSource(DSDesigner.getInstance());
   }
}
/**
 * Codigo Fuente DSDesigner
 */
public class DSDesigner extends RestDataSource{

 private static DSDesigner instance = null;
 
 public static DSDesigner getInstance() {
  if (instance == null) {
   instance = new DSDesigner();
  }
  return instance;
 }//end function
 
 private DSDesigner()
 {
  OperationBinding fetch = new OperationBinding();
  fetch.setOperationType(DSOperationType.FETCH);
  fetch.setDataProtocol(DSProtocol.POSTPARAMS);

  OperationBinding add = new OperationBinding();
  add.setOperationType(DSOperationType.ADD);
  add.setDataProtocol(DSProtocol.POSTPARAMS);

  OperationBinding remove = new OperationBinding();
  remove.setOperationType(DSOperationType.REMOVE);
  remove.setDataProtocol(DSProtocol.POSTPARAMS);

  OperationBinding update = new OperationBinding();
  update.setOperationType(DSOperationType.UPDATE);
  update.setDataProtocol(DSProtocol.POSTPARAMS);

  this.setOperationBindings(fetch, add, remove, update);
  this.setDataFormat(DSDataFormat.JSON);
  
  this.setFetchDataURL("fetch.php");
  this.setAddDataURL("add.php");
  this.setUpdateDataURL("update.php");
  
  DataSourceIntegerField id = new DataSourceIntegerField("id");
  id.setPrimaryKey(true); 
 
  DataSourceTextField nombres = new DataSourceTextField("nombres");
  
  RegExpValidator maskDni=new RegExpValidator();
  maskDni.setErrorMessage("dni es invalido");  
  maskDni.setExpression("[0-9]{8}");  
        
  DataSourceTextField dni = new DataSourceTextField("dni");
  dni.setValidators(maskDni);
  dni.setLength(8);
  
  RegExpValidator maskEmail=new RegExpValidator();
  maskEmail.setErrorMessage("e-mail es invalido");  
     maskEmail.setExpression("^([a-zA-Z0-9_.\-+])+@(([a-zA-Z0-9\-])+\.)+[a-zA-Z0-9]{2,4}$");  
           
  DataSourceTextField email = new DataSourceTextField("email");
  email.setValidators(maskEmail);
  
  this.setFields(id,nombres,dni,email);
  
 }//end functiono
 
}//end class
<?php
/*
* Codigo fuente de add.php
*/
$data=array();
$data[0]["id"]=$_POST["id"];
$data[0]["nombres"]=$_POST["nombres"];
$data[0]["dni"]=$_POST["dni"];
$data[0]["email"]=$_POST["email"];
 
$mensaje=array();
$mensaje["response"]["status"]=0;
$mensaje["response"]["data"]=$data;
 
echo json_encode($mensaje);
?>
<?php
/*
* Codigo fuente de fetch.php
*/
$data=array();
$data[0]["id"]=1;
$data[0]["nombres"]="Sanjiv Jivans";
$data[0]["dni"]="86763232";
$data[0]["email"]="sanjiv@smartgwt.com";
 
$data[1]["id"]=2;
$data[1]["nombres"]="Eric Clayberg";
$data[1]["dni"]="89328745";
$data[1]["email"]="eric@gwtdesigner.com";
 
$data[2]["id"]=3;
$data[2]["nombres"]="Fabien Potencier";
$data[2]["dni"]="84563245";
$data[2]["email"]="fabien@symfony.com";
 
$mensaje=array();
$mensaje["response"]["status"]=0;
$mensaje["response"]["data"]=$data;
 
echo json_encode($mensaje);
?>
<?php
/*
* Codigo fuente de update.php
*/
$data=array();
$data[0]["id"]=$_POST["id"];
$data[0]["nombres"]=$_POST["nombres"];
$data[0]["dni"]=$_POST["dni"];
$data[0]["email"]=$_POST["email"];
 
$mensaje=array();
$mensaje["response"]["status"]=0;
$mensaje["response"]["data"]=$data;
 
echo json_encode($mensaje);
?>