Geek & Roll » programacion

Formas dinámicas con GWT

Cesar March 8th, 2010 javascript, programacion Haz un comentario

Mi relación con GWT es una de amor – odio. Por un lado, tenemos a un toolkit que me permite utilizar mis conocimientos de Java para crear aplicaciones Web dinámicas, aplicando mejores prácticas en la arquitectura del código del cliente, mejorando el tiempo de respuesta gracias al uso de técnicas como agrupar imágenes para usarlas en el cliente con una sola descarga y código segmentado.

Por el otro lado, algunas tareas se vuelven más complicadas. Estoy convencido que las herramientas como GWT son el futuro, más no me queda claro si la actual implementación sea adecuada para toda la programación del lado del cliente. Además la curva de aprendizaje es más inclinada de lo que debería de ser; existen muchos gotchas todavía que hacen que el programador tenga que estar consciente de que esto es Web y no una aplicación regular.

En esta ocasión el requerimiento era el siguiente: tengo una aplicación que hace uso extensivo de formas para captura de datos. Necesito una manera de declarar dichas formas y que la aplicación automáticamente las ordene en diferentes tabs cuando estas crezcan demasiado. Las formas generadas deben poder ser insertadas en cualquier sitio, además de poder aplicarles estilos con CSS.

Como dije anteriormente, lo que me gusta de GWT es que puedo generar la solución a mis requerimientos de la misma manera en la que estoy acostumbrado a hacerlo. En este caso, creo una clase DynaForm que representa mi forma dinámica:

/*Represents the client side DynaForm*/
public class DynaForm {
	private String formSource;
	private ArrayList<String> panelTitles;
	private ArrayList<HTML> panels;
	private Node root;

	public DynaForm(String formSource){
		setFormSource(formSource);
	}

Ahora viene algo interesante. El método setFormSource(). Es aquí donde vamos a parsear el código de la forma para extraer los valores que nos interesan, y descomponerla en sus partes para después volverla a construir pero con las propiedades que nos interesan, en este caso los tabs.

public void setFormSource(String formSource){
	try{
		Document d = XMLParser.parse(formSource);
		root = d.getFirstChild();
		XMLParser.removeWhitespace(root);
		setPanels(root, formSource);
	}catch(Exception e){
		System.out.println(e.getMessage());
		e.printStackTrace();
	}

	this.formSource = formSource;
}

Como vemos, parseamos la fuente y de esa manera nos aseguramos que es código válido. Aquí podríamos aplicar otras reglas, como por ejemplo eliminar cualquier tag o propiedad maliciosa como una llamada a JavaScript. El método setPanels() es el que se encarga de construir los páneles necesarios.

/*
 * This method creates an array of HTML panels. Both panels and panelTitles must
 * contain the same number of elements. In case a <span> element doesn't provide
 * a 'name' attribute, it is replaced by an empty string.
 *
 * The number of HTML panels created is = # of <span> elements. All elements inside <form>
 * without a <span> are ignored.
 * */
private void setPanels(Node root, String formSource){
	panelTitles = new ArrayList<String>();
	panels = new ArrayList<HTML>();
	NamedNodeMap attribs;

	NodeList allElements = root.getChildNodes();

	/*
	 * Start looping all elements, and create new HTML panels as needed
	 * */
	for(int i=0; i<allElements.getLength(); i++){
		Node n = allElements.item(i);
		//if it's a span, create a new empty HTML panel and set its name.
		if(n.getNodeName().equals("span")){
			//Set the panel title entry
			attribs = n.getAttributes();
			panelTitles.add(getAttribValue(attribs, "name"));
			panels.add(new HTML());
		}else{
			try{
				//get the last panel
				HTML panel = panels.get(panels.size()-1);
				//add the node source to the panel HTML
				panel.setHTML(panel.getHTML() + n.toString());
			}catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
	}
}

El método setPanels() toma todos los elementos de la forma y los analiza de la siguiente manera: Si es un elemento span, quiere decir que es el inicio de un nuevo tab. Toma la propiedad name del span y lo convierte en el título de la nueva tab. Si el elemento no es un span, entonces lo agrega a la lista de elementos que forman el tab actual.

Después, en el punto de entrada de la aplicación:

TabPanel tabPanel = new TabPanel();
dynaForm = new DynaForm(formSource);

//All each HTML panel to the tabPanel
for(int i=0; i<dynaForm.getPanels().size(); i++){
	quirksTabPanel.add(dynaForm.getPanels().get(i), dynaForm.getPanelTitles().get(i));
}

RootPanel.get("dynaForm").add(tabPanel);

Utilizando el siguiente código HTML como fuente de la forma:

<form method='POST' action='contactengine.php' name='contact'>
	<span name='Datos' />
	<label for='Nombre'>Nombre:</label>
    	<input type='text' name='Nombre' id='Nombre' />"

    	<label for='Correo'>Correo:</label>
    	<input type='text' name='Correo' id='Correo' />

	<label for='Mensaje'>Mensaje:</label>
	<textarea name='Mensaje' rows='20' cols='20' id='Mensaje'></textarea>

	<span name='Enviar' />
	<input type='submit' name='submit' value='Enviar' class='submit-button' />
</form>

El resultado es:
DynaForm

Claro que se deben usar estilos para hacer que la forma se vea más presentable. También creo que se puede lograr exactamente el mismo resultado utilizando una combinación de jQuery, selectores CSS y jQuery UI.

Controles custom en BlackBerry

Cesar February 12th, 2010 gadgets, programacion Haz un comentario

Crear un control custom para una aplicación de BlackBerry es muy similar a crearlo para una aplicación Java con Swing. La arquitectura del toolkit de Swing es una de las cosas que más me gustan de Java, haciendo muy claro el cómo reemplazar algo por una implementación propia.

En este caso, mi requerimiento era tener una gran “palomita” o checkmark cuando cierta variable era verdadera, y una gran cruz o tache cuando la misma variable era falsa. En otras palabras, un checkbox pero con otra interfaz, más bonita (aunque bonita es una variable que depende del observador, y como eso no lo puedo controlar…)

Como muchas cosas en Java, todo comienza extendiendo una clase, en este caso la clase CheckboxField

public class CustomCheckBox extends CheckboxField

Este checkbox, contrario al checkbox normal, no va a tener un texto asociado, solo la parte gráfica. Así que sobreescribimos el constructor:

public CustomCheckBox(){
	super();
}

public CustomCheckBox(boolean check){
	super("",check);
}

Similar a Swing, hay que sobreescribir el método paint para ahí pintar lo que nosotros queremos. Cuando el checkbox esta check dibujamos la palomita, y cuando esta uncheck, dibujamos la cruz:

public void paint(Graphics g){
	if(getChecked()){
		drawCheck(g);
	}else{
		drawCross(g);
	}
}

Esos dos métodos drawCheck y drawCross son los responsables de pintar el control. El método getChecked heredado de CheckboxField nos dice si el control esta checked o unchecked.

Primero veamos drawCheck

private void drawCheck(Graphics g){
	int left = getBorderLeft();
	int top = getBorderTop();

	int x0 = left, x1 = x0, x2 = x1+20, x3 = x2+50, x4 = x3,
		x5 = x4-50, x6 = x5-20;
	int y0 = top, y1 = y0+30, y2 = y1+15, y3 = y2-45,
		y4 = y3+25, y5 = y4+45, y6 = y5-15;

	g.setColor(0x5B9058);
	g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
	drawBackground(g);
	g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);

	int[] xPts = {x1, x2, x3, x4, x5, x6};
	int[] yPts = {y1, y2, y3, y4, y5, y6};
	g.drawFilledPath(xPts, yPts, null, null);

	g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
}

De antemano perdonen ustedes el uso de números mágicos. Lo interesante es el método drawFilledPath, que toma dos arreglos con coordenadas XY y dibuja, como su nombre lo indica, un polígono. Es algo como dibujar con Logo, uno de mis primeros lenguajes de programación muy similar a Lisp. Primero preparamos las coordenadas, después verificamos si nuestro control tiene el foco para dibujarle un fondo distintivo.

El otro método, drawCross, es muy parecido solo que las coordenadas cambian para formar una cruz:

private void drawCross(Graphics g){
	int left = 0;
	int top = 10;

	int x0 = left, x1=x0, x2=x1+25, x3=x2+10, x4=x3+10, x5=x4+25,
		x6=x4+5, x7=x5, x8=x4, x9=x3, x10=x2, x11=x1, x12=x2-5;
	int y0 = top, y1=y0,y2=y1, y3=y2+15, y4=y2, y5=y4, y6=y5+25,
		y7=y6+25, y8=y7, y9=y8-15, y10=y8, y11=y10, y12=y6;

	g.setColor(0xB54E41);
	g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
	drawBackground(g);
	g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);

	int[] xPts = {x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12};
	int[] yPts = {y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12};
	g.drawFilledPath(xPts, yPts, null, null);

	g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
}

Y finalmente la clase completa

public class CustomCheckBox extends CheckboxField{
	public CustomCheckBox(){
		super();
	}

	public CustomCheckBox(boolean check){
		super("",check);
	}

	public void paint(Graphics g){
		if(getChecked()){
			drawCheck(g);
		}else{
			drawCross(g);
		}
	}

	protected void drawFocus(Graphics g, boolean focus){
		//do nothing
	}

	protected void onFocus(int direction){
		super.onFocus(direction);
		invalidate();
	}

	protected void onUnfocus(){
		super.onUnfocus();
		invalidate();
	}

	protected void layout(int width, int height){
		width = 71;
		height = 71;
		setExtent(width, height);
	}

	private void drawCheck(Graphics g){
		int left = getBorderLeft();
		int top = getBorderTop();

		int x0 = left, x1 = x0, x2 = x1+20, x3 = x2+50, x4 = x3,
			x5 = x4-50, x6 = x5-20;
		int y0 = top, y1 = y0+30, y2 = y1+15, y3 = y2-45,
			y4 = y3+25, y5 = y4+45, y6 = y5-15;

		g.setColor(0x5B9058);
		g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
		drawBackground(g);
		g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);

		int[] xPts = {x1, x2, x3, x4, x5, x6};
		int[] yPts = {y1, y2, y3, y4, y5, y6};
		g.drawFilledPath(xPts, yPts, null, null);

		g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
	}

	private void drawCross(Graphics g){
		int left = 0;
		int top = 10;

		int x0 = left, x1=x0, x2=x1+25, x3=x2+10, x4=x3+10, x5=x4+25,
			x6=x4+5, x7=x5, x8=x4, x9=x3, x10=x2, x11=x1, x12=x2-5;
		int y0 = top, y1=y0,y2=y1, y3=y2+15, y4=y2, y5=y4, y6=y5+25,
			y7=y6+25, y8=y7, y9=y8-15, y10=y8, y11=y10, y12=y6;

		g.setColor(0xB54E41);
		g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
		drawBackground(g);
		g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);

		int[] xPts = {x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12};
		int[] yPts = {y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12};
		g.drawFilledPath(xPts, yPts, null, null);

		g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
	}

	private void drawBackground(Graphics g){
		g.clear();
	}

	public boolean isFocusable(){
		return true;
	}
}

El resultado:
customcheckbox

Look ma! custom controls with no images!

Desarrollo de software en un mundo post-agil

Cesar February 9th, 2010 opinion, programacion, tips 1 comentario

Del artículo:

Un proceso es un instrumento de autoridad. Un proceso es una proclamación de qué hacer, cómo debemos de hacerlo y en qué orden. Un proceso es conservador, jerárquico y formal. Un proceso mantiene el status quo. Es la administración imponiendo orden y control desde arriba. Si los procesos fueran un partido político, sería de derecha.

Es fácil ser seducido por las bondades de la metodología ágil. Promesas de equipos auto suficientes, entregas frecuentes y listas para producción, Yippi-kay-ay. Demasiado proceso y en vez de avanzar nos quedamos llenando reportes y formas; muy poco proceso y todo se vuelve un manojo de actividad descontrolada y poco empuje (y entrega).

El artículo discute la etiqueta “ágil” que tanto se usa en administración de proyectos de software hoy en día. Por ahí leí que “scrum” (intercambiado por ágil en esta ocasión) no es una bala de plata para tener proyectos exitosos. Existen factores como la experiencia y motivación del equipo, así como también la naturaleza del proyecto, por lo que una aproximación orientada a personas tiene más sentido que orientado a procesos, y viceversa.

Lean el artículo fuente (en Inglés), y los invito a dejar sus comentarios sobre el tema, experiencias personales, etc.

Quitándole el ruido a twitter moviendo los hashtags

Últimamente he estado pensando en el principal problema de twitter (aparte de la estabilidad): el ruido. Es dificil separar la información “real” del ruido que llegamos a tener en nuestra timeline de un solo vistazo. Esta es una propuesta pequeñita de mejora:

Una de las principales fuentes de ruido son los hashtags (palabras “marcadas” que se utilizan para ayudar en la búsqueda). Hay gente que termina dedicando incluso más caracteres a los hashtags que al post en si.

Mi propuesta de 15 minutos no implica cambiar el funcionamiento de la publicación de hashtags, sino separarlos (por medio de programación) del contenido del post. Se entiende mejor con un ejemplo (click en las imágenes para ver a tamaño completo):

Este es un tweet normal:

Y este es uno con los hashtags separados del contenido del post.

A mi me parece que la diferencia, aunque en un sólo tweet se ve pequeña, sería de gran ayuda al leer Twitter por medio del sitio web.

No pretendo que esto llegue hasta twitter (ni que fuera la gran cosa), pero si a alguien le interesa, sería más o menos sencillo de implementar en un userscript de greasemonkey.

Antes de que digan cualquier cosa, si, ya estamos pensando en que cuando aparezca mi sección diga “tweet & roll” en el header.

Uso de enum en Grails

Cesar May 18th, 2009 programacion 3 comentarios

O “El diablo está en los detalles”.

Recientemente he estado usando Grails como framework para desarrollo Web con Java y, francamente, estoy bastante sorprendido. Realmente es un boost a la productividad, tanto que una vez que terminé mi diagrama UML del dominio de mi primera aplicación en Grails y comencé a programar las clases de dominio, no podía creer que esas mismas clases fueran las que se usarían para persistir en la base de datos. No hay que crear archivos hbm.xml ni configurar Spring. Sólo crear la clase del dominio, y ya.

Después de varias sesiones nocturnas de un par de horas leyendo sobre Grails, y viendo el código que genera el scaffolder incluído, empecé a crear mis controladores, vistas, refactorizando el modelo. Todo iba bien hasta que me topé con la necesidad de usar datos enumerados (enums).

La solución en sí es sencilla. El problema es que no existe documentación suficiente para utilizar enums con Grails. Después de consultar distintas fuentes e invertir buena parte de mi Domingo en dar con la solución, aquí les presento el código con el que pueden lograr utilizar enums en Grails. Leer el resto de este post.

La regla noventa-noventa

Axel April 21st, 2009 lol, programacion 1 comentario

El primer 90% del código toma 90% de tiempo de desarrollo. El 10% restante de código toma el siguiente 90% del tiempo de desarrollo. Tom Cargill.

Algo que todo project manager debería tener presente ;)

Soñando CSS pidata

Axel April 6th, 2009 lol, programacion 2 comentarios

Axel: Wey, soñé una onda bien curada
Rafyta: ¿Qué?
Axel: que definía behavior dentro del CSS
Axel: por ejemplo: #elemento:click { .bloques: fadeout() }
Axel: Está curadísimo, sería sencillo hacer un parser para aplicar las func…
Rafyta: http://yellowgreen.de/morecss
Axel:
Axel: FUCK!

No sé que es peor, si soñar con CSS y Javascript o tener un sueño “pidata”.

Cambio de enfoque en Geek & Roll

Cesar April 1st, 2009 FLOSS, linux, opinion, programacion, windows 5 comentarios

Por si quedaba duda, fue April’s fool.

Esto es algo de lo más difícil que me ha tocado escribir desde que decidí iniciar un weblog. A lo largo de los años he defendido el modelo de fuente abierta, el Software Libre, el uso de GNU/Linux y los formatos abiertos.

Como sabrán, en el trabajo me he visto en la necesidad de usar día a día Windows Vista, y aunque puedo ver muchas de sus deficiencias, también he visto algunas de las características que hacen de Windows un sistema operativo tan atractivo para tantas personas. Probando el beta de Windows 7 no pude dejar de pensar en querer algo así para mi computadora.

Y bién, dicen que reconocer el error es de sabios. Más aún corregirlo. Después de batallar más de dos días tratando de instalar Netbeans y Grails en mi laptop personal, terminé por instalar Windows 7 y no puedo estar más contento. Junto con Windows Vista en mi laptop de trabajo, forman mi ecosistema de cómputo 100% Windows. Ahora soy más productivo y feliz.

Por lo mismo no esperen ver más artículos sobre GNU/Linux, ahora me enfocaré en programación para la plataforma Windows, .NET y programas disponibles para Windows.

Entrevista a Santiago Zavala, programador de Tikkia

Hoy por la mañana descubrimos el sitio www.tikkia.com, el cual es una red social enfocada a profesionistas del área de las TI en Latinoamérica, creada por el mismo grupo responsables de la Super Happy Dev House México. Después de probar un poco el sitio que se encuentra en fase Beta decidimos hacerle una pequeña entrevista a Santiago Zavala, programador de Tikkia y responsable de asuntos internacionales del sitio. La entrevista después del salto.

Leer el resto de este post.

Everlasting Flame 1.2 – Bilingüe

Cesar February 18th, 2009 FLOSS, aplicaciones, gadgets, programacion 38 comentarios

Everlasting Flame icon


Edit: ELF 1.2 ha salido a la luz. Visiten http://www.cesarolea.com/everlastingflame/ para mas detalles.

El mejor (¿único?) auto hangup para BlackBerry, Everlasting Flame (ELF para los amigos), se encuentra muy próximo a pasar a su versión 1.2. La novedad principal es que ahora la interfaz gráfica es bilingüe, dependiendo de la configuración de localización de la BlackBerry, todo el texto cambia de Inglés a Español. Claro, soporte para más idiomas es trivial de agregar, siempre y cuando alguien me mande la traducción del texto :)

Hay dos cosas como prioridad para la versión 1.3:

  • Remarcado automático después de que la llamada se termine
  • Reescritura de la arquitectura de las opciones para hacer el sistema más flexible y robusto (y espero que con menos bugs)

El remarcado automático actualmente falla al querer reiniciar una llamada. La API te permite invocar a la aplicación del teléfono (a través de la clase Phone) y pasarle un número pero al terminar la llamada esta aplicación ya está abierta, por lo tanto no sirve. Inyectando la tecla Send tampoco funciona. Tengo que encontrar una forma de ser notificado cuando la aplicación Phone regrese a su pantalla inicial (la de tiene el historial de números marcados) y entonces intentar automatizar el menú para iniciar la llamada.

La reescritura de la arquitectura de las opciones es algo que sabía que llegaría eventualmente. Si se desean agregar más opciones se tiene que evitar los largos bloques condicionales anidados que son fuente de errores y nada extendibles. No serán características que tengan un impacto directo para las características del programa, pero son bases sólidas para poder continuar agregando características útiles.

Visiten el sitio oficial del proyecto, descárguenlo, úsenlo, reporten errores y sugieran características. Si EFL les es de utilidad, no se olviden de contribuir, donando cualquier cantidad de dinero (ya se puede por paypal), lo que anima al equipo de desarrollo (o sea yo) a seguir con el proyecto. También se puede colaborar escribiendo documentación, traduciendo y programando.

Posts anteriores