En este artículo os contaré cómo usar datos de tipo Texto en los Informes que no dependen de Orígenes de datos de tablas Velneo y cómo resolver la impresión de textos girados, algo que ya hace el editor de Informes pero con algunos problemas.
Datos de tipo Texto en los Informes
Como ya sabemos, un Informe personalizable debe tener siempre asignada una Entrada de tipo Lista para que pueda ejecutarse mediante los comandos de Informe personalizable. Sin embargo no es necesario que los registros de la Entrada de tipo Lista alimenten las secciones de Detalle, es decir, podemos usar otros tipos de Orígenes de datos distintos al de «Tabla de Velneo«.
A la hora de definir el Origen de datos el editor de Informes nos propone hasta seis Tipos distintos. En este artículo vamos a utilizar el tipo Texto y comprobaremos qué posibilidades nuevas nos aporta.
Seleccionamos la localización Estático para los datos de tipo Texto, lo que significa que dichos datos deben estar incluidos en la definición del Informe, es decir, se guardarán en un Tag del archivo XML.
El Origen de datos Tabla de Velneo también es de Tipo de localización Estático porque el alias del proyecto y la tabla de Velneo se guardan en la definición del Informe para generar el modelo de datos Qt que alimentará el Informe.
Las propiedades del Origen de datos de tipo Texto son:
- Delimitador de columna: normalmente será un tabulador aunque podemos seleccionar otros
- Codificación del Texto: normalmente UTF-8
- La primera fila actúa como cabecera de columnas
- Texto estático: columnas de datos separadas con el delimitador de columna
Que los datos de tipo Texto estático estén incluidos en el archivo XML facilita enormemente la personalización del Informe ya que solo tenemos que parsear y editar el contenido de la estructura XML. De esta forma podemos diseñar un módulo que permita al Usuario final incorporar y editar el Texto estático en el archivo XML, evitando que tenga que aprender a usar el editor de Informes.
La plataforma Velneo no nos proporciona herramientas adecuadas para el parseo y edición de documentos XML. Nuestro compañero Cristian ha desarrollado un módulo que convierte el XML a Json facilitando el parseo enormemente. Nos faltaría el módulo de conversión JsonToXml, aunque Cristian me ha prometido que se pone a ello inmediatamente.
Ahora podemos preguntarnos qué utilidad tiene esto. Veamos dos ejemplos para intentar aclararlo.
Datos fijos en el Informe
Si en nuestras aplicaciones utilizamos plantillas y distribuimos los Informes personalizables, estos tendrán datos fijos propios de cada cliente destinatario.
Por ejemplo, en el Informe creamos un Origen de datos de tipo Texto con Id DATOS_FIJOS y con 4 columnas que queremos que aparezcan siempre en la Cabecera de los Informes de la Aplicación.
El Origen de datos DATOS_FIJOS solo contiene un registro y no está asociado a ninguna sección de Detalle, sin embargo tiene el rol de Comienzo del Informe, por lo que en la Cabecera de página tendremos acceso al único registro con los datos fijos.
Los Orígenes de datos que no están asociados a una sección de Detalle y tienen el rol de Comienzo del Informe se cargan siempre al inicio del Informe. De esta forma podemos usar listas de Velneo de un solo registro de la misma manera que usamos los Datos de tipo Texto de este ejemplo. También se puede ver como otra forma de pasar parámetros al Informe personalizable.
Lista de datos no Velneo
En muchas ocasiones las aplicaciones generan o reciben datos encolumnados que deben imprimirse. Para ello necesitaríamos crear una tabla temporal que alimente la Entrada del informe personalizable. Otro escenario es cuando tenemos que enviar Demos de nuestros Informes y necesitamos datos con los que llenarlos.
Con un Origen de datos de tipo Texto estático podemos crear un Informe personalizable que contenga al mismo tiempo la definición del Informe y los datos que se van a imprimir, sin depender de tablas Velneo específicas.
En el ejemplo siguiente se ha insertado una Lista de 4 columnas de datos en el campo Texto estático del Origen de datos con Id LISTA_TEXTO.
La sección de Detalle TEXTOS tiene asignado el Origen de datos LISTA_TEXTO y los elementos de Campo se insertan en el Informe de la forma habitual. Tenemos que tener en cuenta sin embargo que el botón del Editor de fórmulas de Velneo ya no funciona para los Orígenes de datos que no son de Velneo. En su lugar usaremos el botón del Asistente de scripts para seleccionar los campos del Origen de datos.
Estamos usando el Tipo de localización estático para el Origen de datos, pero podemos usar también el Tipo de localización fichero e indicar el path del fichero. En lugar de tener los datos incrustados en el archivo XML el Informe cargará el archivo de texto desde el disco.
Ejecutando los Informes personalizables con datos de Tipo Texto
Imaginamos la situación en la que nuestra aplicación debe enviar un Informe personalizable con Datos fijos en la Cabecera y una lista de datos estáticos incrustada en el archivo del Informe.
Ya hemos dicho que para ejecutar el Informe no tenemos más remedio que alimentarlo con una Entrada de tipo Lista de Velneo. Como no vamos a imprimir datos de Velneo será suficiente con cargar una tabla temporal sin registros. Cualquier tabla temporal nos servirá porque no la vamos a usar en los Orígenes de datos del Informe.
Hay una excepción, la lista de Entrada deberá tener al menos un registro si queremos insertar expresiones con el editor de fórmulas de Velneo. El Origen de datos no puede estar vacío si se van a usar expresiones relacionadas con elementos del proyecto de datos de Velneo. Lo veremos más adelante en el ejemplo de texto girado y dinámico.
El Informe solo contendrá dos Orígenes de datos de tipo Texto estático con Id’s DATOS_FIJOS y LISTA_TEXTO. Solo nos falta un proceso que abra el archivo XML e inserte los datos estáticos en los Tags respectivos antes de enviar o imprimir el Informe.
Girar textos en los Informes personalizables
El editor de Informes personalizables puede girar los elementos Etiqueta y Campo. Lo que ocurre es que hay muchos problemas tanto en el editor como en el previsualizador de Informes.
Voy a proponeros una alternativa usando las imágenes SVG incrustadas en la definición del Informe. Las imágenes SVG definen gráficos vectoriales en formato XML y por lo tanto fácilmente editables.
La idea es crear la imagen SVG a partir del texto, tipo de letra, tamaño, alineamiento y ángulo de giro.
Por ejemplo, un texto en formato SVG que va a estar girado
270º (o -90º) se define de la siguiente forma:
<svg viewBox='-15 -132 18 132'>
<rect x='0' y='-15' transform='rotate(-90,0,0)' width='132' height='18' stroke-width='1' stroke='Silver' fill='none'/>
<text x='0' y='-1' text-anchor='start' transform='rotate(-90,0,0)' font-family='verdana' font-size='16' font-weight='normal' fill='black'>
Izquierda -90º
</text>
</svg>
El código SVG define dos elementos, un rectángulo rect y el texto text. Todas las cantidades están expresadas en pixeles.
- El elemento rect muestra la Caja de texto: los atributos width y height son las dimensiones que ocupará en el Informe.
Podemos ocultar el rectángulo haciendo stroke-width=’0′. - El elemento text determina el aspecto del texto: el atributo text-anchor señala el alineamiento izquierda (start) o derecha (end).
- El atributo transform ejecuta una rotación que en nuestro caso irá de -90º a 90º.
Para insertar el texto girado en formato SVG usamos el elemento Imagen del editor de Informes.
- Seleccionamos el Tipo de origen del ítem Estático para que el código SVG se incruste en el archivo XML del Informe.
- El Formato de imagen será Formato SVG para que el editor inserte de manera correcta el código SVG
- Desde un archivo temporal en disco podemos leer el código SVG.
- La opción de proporción siempre debe estar en Mantener para que el texto no se deforme en el editor del Informes.
Para generar el código SVG disponemos de muchos editores en
el mercado. Como el código SVG es relativamente sencillo y somos programadores,
podemos plantearnos la opción de crear un módulo Editor de textos SVG con rotación.
En Velneo disponemos del objeto Imagen SVG, pero lamentablemente y como suele ocurrir con muchos otros objetos nativos, está incompleto:
- No se puede cargar código SVG de forma dinámica desde un string o ByteArray, solo es posible desde un objeto estático del proyecto o desde fichero.
- Lo más grave e incomprensible es que la opción de proporción siempre es Ignorar por lo que no podemos escalar la imagen sin deformarla.
Son dos limitaciones que Velneo no soluciona y como otras muchas veces debemos recurrir a librerías externas u otras opciones. Afortunadamente en Qt han hecho bien su trabajo y en QML disponemos del tipo Image que renderiza correctamente el código SVG.
En el siguiente código QML solo tenemos que guardar en cSVG la definición del Texto en formato SVG y obtendremos un previsualizador dinámico de imagenes SVG en nuestros formularios.
Image {
id: imgSVG;
// Image.Pad, Image.PreserveAspectCrop, Image.PreserveAspectFit;
fillMode: Image.Pad;
cache: false;
source: "data:application/svg," + **cSVG**;
}
Ya disponemos entonces de todo lo necesario para crear nuestro módulo Editor de textos SVG con rotación:
- Parser XML que lea el archivo XML del Informe y obtenga un objeto Json desde el que podamos obtener los elementos image con Id de ítem que comienzan con SVG_. Cuidado con el Id de ítem porque copiar y pegar un elemento en el editor de Informes reinicia el valor dado al Id.
#include "6x7p84ml.vcd/xml_parser.js"
// Parser XML a Json usando el plugin de Cristian ¡¡Magnífico!!
var oParser = new cirrusXML(theRoot.varToString("CXML"))
// Buscamos en un Array los Nodos image SVG (format = "2") de tipo estático
var aResul = oParser.find(function(node) {
return (
**node.nodeName == "image" &&**
**node.attrs.format == "2" &&**
**node.attrs.id.match(/SVG\_/) &&**
**node.attrs.resource == null**
)
});
theRoot.setVar("CJSON", JSON.stringify(aResul))
Los elementos image en el archivo XML con los textos SVG tienen el siguiente contenido:
<**image** **id="SVG\_**I-90" zValue="13" posX="134.620" posY="15.240" width="5.080" height="34.925" aspectRatio="keep" **format="2"** alignment="1">
**<svg viewBox='-15 -132 18 132'>**
**<rect x='0' y='-15' transform='rotate(-90,0,0)' width='132'
height='18' stroke-width='1' stroke='Silver'** **fill='none'/>**
**<text x='0' y='-1' text-anchor='start' transform='rotate(-90,0,0)' font-family='verdana' font-size='16' font-weight='normal' fill='black'>**
**Izquierda -90º**
**</text>**
**</svg>**
</image>
El atributo format = 2 indica que la imagen es de formato SVG. Para desechar las imágenes SVG cargadas desde disco buscamos aquellas cuyo atributo resource no exista.
- Desde la variable local CJSON, que contiene el array Json con los elementos image, se rellena una tabla temporal. Guardamos en el campo svg de la tabla el código SVG de la propiedad _text.
Objeto Json después de parsear el archivo XML
{ "nodeName": "image",
"attrs": {
"id": "SVG_I-90",
"zValue": "13",
"posX": "134.620",
"posY": "15.240",
"width": "5.080",
"height": "34.925",
"aspectRatio": "keep",
"format": "2",
"alignment": "1"
},
"**\_text**": "**<svg viewBox='-15 -132 18 132'>\n <rect x='0' y='-15' transform='rotate(-90,0,0)' width='132' height='18' stroke-width='1' stroke='Silver' fill='none'/>\n <text x='0' y='-1' text-anchor='start' transform='rotate(-90,0,0)' font-family='verdana' font-size='16' font-weight='normal' fill='black'>\n Izquierda -90º\n </text>\n</svg>**"
}
- Formulario QML que alimentamos con el registro de la tabla temporal y previsualizamos el texto girado mediante el tipo QML Image.
- Para cambiar el aspecto del texto y el ángulo de giro editamos los atributos rotate y font.
- El rectángulo rect nos muestra el recuadro que ocupa el texto en el Informe. Los atributos width y height están en pixeles. Para conocer el tamaño en el Informe tendremos que convertirlos a mm, que es la unidad del editor de Informes (1px = 25.4/96mm).
- Una vez finalizada la edición de los textos ya podemos reponer los elementos image en el archivo XML. Los textos SVG aparecerán en el editor y si es necesario ajustamos los valores Ancho y Alto en el Editor de geometría con los valores en mm.
Texto girado y dinámico
Llegará un día en que nos pidan un Informe con el texto de «Pag. pageno de pagecount» en un lateral de la página y girado 90º. Con lo visto en este artículo ya puedes decir que es posible, no tienes más que diseñar el código SVG construyendo el texto con las variables pageno y pagecount del Informe.
Pero hay un problema, la imagen SVG es distinta en cada página del Informe ya que el texto debe generarse de forma dinámica en el momento en que es impreso en el Informe. El origen del código SVG ya no puede ser estático, tenemos que usar una función que reciba los parámetros pageno y pagecount. para construir el texto que corresponda.
Desde un Informe personalizable se pueden ejecutar funciones del proyecto de datos, aunque pronto nos damos cuenta que no podemos pasar como parámetros los valores de las variables pageno y pagecount. Tenemos que buscar otra forma de generar el texto dinámicamente.
Ya hemos dicho antes que para usar expresiones del entorno Velneo desde un Informe, el Origen de datos de la tabla Velneo debe tener al menos un registro. Por lo tanto, en nuestro ejemplo de Origen de Texto estático tendremos que añadir a la tabla temporal un registro y definir un Origen de datos para esta tabla temporal.
Lo que vamos a hacer es usar variables Globales para calcular los valores de pageno y pagecount. Ya sabemos que el valor de pagecount se calcula cuando activamos el Modo de pasada doble en el Informe.
En el Modo de pasada doble el Informe se ejecuta 2 veces, una primera vez para calcular el pagecount y una segunda vez para imprimir el informe definitivo. Para saber desde Velneo en qué pasada está el Informe ejecutamos una función desde la Sección Cabecera del Informe, ya que solo se ejecuta una vez en cada pasada del Informe.
La función FUN_CONTAR_PASADAS
guardará en la variable Global G_INF_NUM_PASADA
un valor 2 cuando el Informe se ejecuta en la segunda pasada.
Función: **FUN\_CONTAR\_PASADAS**
**Rem ( Cuando se imprime el Informe el valor de G\_INF\_NUM\_PASADA será 2 )**
Modificar variable global ( G_INF_NUM_PASADA@0PS_ARTIPACO_dat, $G_INF_NUM_PASADA@0PS_ARTIPACO_dat.dat+ 1, )
En el editor de Informes insertamos la Imagen SVG, pero en este caso con Origen de datos como el origen del código SVG. Desde el Editor de fórmulas de Velneo introducimos la llamada a la función nativa FUN_NUMPAG_SVG que devolverá el código SVG con el texto dinámico a partir de las variables Globales G_INF_PAG_NUM y G_INF_PAG_TOTAL. En la segunda pasada la variable Global G_INF_PAG_TOTAL contendrá un valor igual a pagecount.
Función: **FUN\_NUMPAG\_SVG**
**Rem ( Función que podemos ejecutar desde el Informe para devolver un SVG con el texto Pág N de TotalPag )**
**Rem ( Se ejecuta en la Cabecera (LCABECERA = 1) o Pie del informe desde un elemento Imagen SVG )**
Libre
**Rem ( La variable G\_INF\_NUM\_PASADAS se calcula desde el Script de "Imprimir si ..." de la Sección Cabecera de Informe para saber en qué Nº de pasada estamos )**
Libre
**Rem ( TOTAL DE PÁGINAS. Se totaliza en la 1ª pasada del Informe )**
If ( $**G\_INF\_NUM\_PASADA**@0PS_ARTIPACO_dat.dat **= 1** )
Modificar variable global ( **G\_INF\_PAG\_TOTAL**@0PS_ARTIPACO_dat, $G_INF_PAG_TOTAL@0PS_ARTIPACO_dat.dat+ 1, )
Libre
**Rem ( Nº DE PÁGINA. Solo se incrementa en la 2ª pasada )**
If ( $**G\_INF\_NUM\_PASADA**@0PS_ARTIPACO_dat.dat **= 2** )
Modificar variable global ( **G\_INF\_PAG\_NUM**@0PS_ARTIPACO_dat, $G_INF_PAG_NUM@0PS_ARTIPACO_dat.dat + 1, )
Libre
**Rem ( Si está en la CABECERA se incrementa en uno )**
Set ( NNUM_PAG, $G_INF_PAG_NUM@0PS_ARTIPACO_dat.dat + LCABECERA )
**Rem ( Devuelve el código SVG )**
Set ( **CSVG**, "<?xml version='1.0' encoding='UTF-8'?> <svg viewBox='-12 -89 14 89'> <text x='0' y='-1'
text-anchor='start' transform='rotate(-90,0,0)' font-family='tahoma' font-size='12' font-weight='bold'
fill='black'> Pág. " + NNUM_PAG + " de " + $G_INF_PAG_TOTAL@0PS_ARTIPACO_dat.dat+ " </text> </svg>" )
Set dato de retorno ( **CSVG** )
Y este es el resultado final.
Conclusión
Bueno, espero que estas dos nuevas posibilidades de aplicación de los Informes personalizables os hayan sacado, aunque sea por un rato, de la monotonía a la que estamos condenados muchas veces en nuestros proyectos.
Los Informes de Texto estático se pueden ejecutar desde cualquier aplicación sin depender de una tabla determinada. Girar textos mediante imágenes SVG nos permite dar un uso a este formato vectorial, que lamentablemente tan abandonado tiene el equipo de desarrollo de Velneo. Quizás en la versión 26 de Velneo se solucione el giro de Textos junto con otras nuevas funcionalidades del Editor de Informes.
Ya imagino que muchos pensaréis que son cosas que nunca váis a usar y que para girar un texto no merece la pena tanto lío. Sin embargo, es lo bueno de Velneo, estar tan limitado en muchas facetas de la programación y el contínuo prueba y error, te obligan a explorar nuevas opciones, que siempre aportarán algo nuevo a nuestro conocimiento.
El artículo va de datos estáticos y girar un texto en un Informe, pero finalmente hemos acabado «parseando» un archivo XML, peleando con Json, exportando a XML nuevamente, construyendo código SVG y previsualizando el resultado con un módulo QML e incluso usamos desde el Informe funciones y variables globales del proyecto de datos. Son cosas de Velneo.
No terminamos aquí, quedan algunas funcionalidades interesantes de los Informes personalizables que iremos viendo en próximos artículos de Velneo a Fondo.
Espero que con este tutorial no te quede ninguna duda sobre imprimir texto girados en informes personalizables de Velneo.