MonoReporter – Reportes en Mono

Ya escribí un post sobre este tema. Desde ahí hasta hace un mes aproximadamente, MonoReporter quedó olvidado, ya que en realidad no lo necesitaba con tanta urgencia… pero ahora sí. Es lo que sigue por hacer en Zaspe#: la generación de reportes.

Mi idea era hacer algo que no sólo me sirva a mí, sino que lo pueda usar otra persona también. Cuando le comenté la idea a Nacho, sobre un lenguaje basado en XML para describir el reporte, me propuso leer un SVG, hecho con Inkscape por ejemplo… así me ahorraría un futuro diseñador de reportes. Eso es lo que he hecho.

MonoReporter entonces lee de un SVG hecho con Inkscape (lo aclaro porque sobre este software hice las pruebas), y lo transforma a instrucciones para dibujar con Cairo y GtkPrint (el nuevo sistema de impresión de Gtk+). Es posible, por ejemplo, exportar directamente a PDF, o mostrar el diálogo de impresión, tanto en GNU/Linux como Windows (previa instalación de los runtimes de gtk-sharp que se pueden encontrar en la web de zaspe#). A esto lo realiza en forma nativa.


Para leer el XML (SVG), simplemente uso las clases en el namespace System.Xml. No utilizo ninguna librería externa. He probado una, SvgNet, un proyecto poco activo (último release en el 2003). Y me he dado cuenta de que tenía que adaptarlo mucho… así que opté por crear mis propias clases de lectura del SVG, que terminó siendo un trabajo bastante sencillo en realidad.

Debido a algunas limitaciones que tengo en Windows (como los bindings de Cairo sólo disponibles para el profile 1.0), el diseño en general de las clases no es el mejor, o por lo menos el que me hubiese gustado.

Este es un ejemplo de uso de MonoReporter con C# (en realidad, se puede utilizar con cualquier lenguaje de .NET):

using System.Data;
using MonoReporter;

...

Report report = new Report("PruebaMonoReporter", "test.svg");
report.Data["titulo"] = "Listado de personas";

DataTable personsTable = new DataTable();

DataColumn[] columns = new DataColumn[4];
columns[0] = new DataColumn("nombre");
columns[1] = new DataColumn("apellido");
columns[2] = new DataColumn("dni");
columns[3] = new DataColumn("direccion");
personsTable.Columns.AddRange(columns);

DataRow d1 = personsTable.NewRow();
d1["nombre"] = "Milton";
d1["apellido"] = "Pividori";
d1["dni"] = "99999999";
d1["direccion"] = "dirección";
personsTable.Rows.Add(d1);

d1 = personsTable.NewRow();
d1["nombre"] = "Pepe";
d1["apellido"] = "Biondi";
d1["dni"] = "11111111";
d1["direccion"] = "alguna dirección";
personsTable.Rows.Add(d1);

d1 = personsTable.NewRow();
d1["nombre"] = "Juan";
d1["apellido"] = "Sanchez";
d1["dni"] = "33333333";
d1["direccion"] = "otra dirección";
personsTable.Rows.Add(d1);

report.DataTables["personas"] = personsTable;

report.Run(myWindow);

DataTable es una clase del namespace System.Data.

Report es una clase de MonoReporter, la principal. En las primeras lineas se crea un nuevo reporte con un título dado, y un archivo SVG de donde leer el diseño del reporte. La propiedad Data devuelve un Hashtable, en el que podemos setear el texto que queramos al elemento SVG indicado por la clave. En este caso, se está diciendo que al momento de generar el reporte, al elemento con id (lo cambiamos desde Inkscape) “titulo” le asigne el valor “Listado de personas”.

Una vez creado el DataTable, le indicamos la fuente de datos para la “tabla” llamada “personas”. Una “tabla” es un concepto inventado, que se forma creando varios elementos de texto en Inkscape, tantos como columnas haya, y dándole a cada uno el nombre de la columna (que definimos en el DataTable). Luego se los agrupa, y a esa agrupación se le coloca un nombre. El nombre en este caso es “personas”.

De esta forma cuando MonoReporter encuentra un layer con sólo nodos “text”, sabe que se trata de una tabla. Este es el archivo PDF final que genera el código de arriba.

Quedan muchas (muchísimas) cosas por hacer, a tal punto de que ni siquiera es usable: por el momento se pueden generar reportes de una sola página 🙂 Algunas cosas que faltan por hacer:

  • Soporte para reportes largos (de más de una página).
  • Soporte para más elementos gráficos de SVG (por ahora reconoce rectángulos, líneas y texto).
  • Mayor nivel de personalización: por ejemplo, el espacio entre filas no se puede cambiar.
  • Soporte para la inclusión de imágenes.
  • Etc etc etc…

Algunas limitaciones:

  • A los textos sólo se los puede redimensionar aumentando su tamaño de fuente, o sea, sin utilizar las flechas.
  • Raramente, algunos colores son bien leidos, pero otros no, como el verde.
  • Y muchas más…

El código fuente se encuentra aquí, en el mismo repositorio que Zaspe#. Está bajo la GPLv3.

Si alguien tiene algún comentario, alguna mejora o sugerencia para encarar esto mejor… bienvenido sea!