<?xml version = "1.0" encoding = "ISO-8859-1"?> <!DOCTYPE editores SYSTEM "dtds/editores.dtd"> <editores> <editor .../> ... </editores>Simplemente contiene la definición de un conjunto de editores, y un editor se define así:
<editor nombre="nombre" <!-- 1 Nuevo en v2.1.3 --> url="url" <!-- 2 --> formatear="true|false" <!-- 3 --> depende-de-estereotipos="estereotipos" <!-- 4 --> depende-de-propiedades="propiedades" <!-- 5 --> enmarcable="true|false" <!-- 6 --> recargar-siempre="true|false" <!-- 7 Nuevo en v3.1.2 --> compuesto="true|false" <!-- 8 Nuevo en v3.1.3 --> icono="icono" <!-- 9 Nuevo en v5.7 --> accion-iniciar="Controlador.accion" <!-- 10 Nuevo en v5.7 --> accion-liberar="Controlador.accion" <!-- 11 Nuevo en v5.7 --> elementos-seleccionables="true|false" <!-- 12 Nuevo en v5.7 --> > <propiedad ... /> ... <!-- 13 --> <formateador ... /> <!-- 14 --> <formateador-lista ... /> <!-- 15 Nuevo en v3.1.4 --> <para-estereotipo ... /> ... <!-- 16 -->
<para-anotacion ... /> ... <!-- 17 Nuevo en v6.6 -->
<para-tipo ... /> ... <!-- 18 --> <para-propiedad-modelo ... /> ... <!-- 19 --> <para-referencia ... /> ... <!-- 20 Nuevo en v3.1.3 --> <para-coleccion ... /> ... <!-- 21 Nuevo en v3.1.3 --> <para-tab ... /> ... <!-- 22 Nuevo en v4.6 --> <para-valores-posibles /> <!-- 23 Nuevo en v2.1.2 --> <para-referencias /> <!-- 24 Nuevo en v3.1.3 --> <para-colecciones /> <!-- 25 Nuevo en v3.1.3 --> <para-colecciones-elementos /> <!-- 26 Nuevo en v5.0 --> <para-tabs /> <!-- 27 Nuevo en v4.6 --> </editor>
<editor url="textEditor.jsp"> <for-type type="java.lang.String"/> <for-type type="java.math.BigDecimal"/> <for-type type="int"/> <for-type type="java.lang.Integer"/> <for-type type="long"/> <for-type type="java.lang.Long"/> </editor>Aquí asignamos a un grupo de tipos básicos el editor textEditor.jsp (podemos encontrarlo en openxava/src/main/resources/META-INF/resources/xava/editors). El código JSP de este editor es:
<%@ page import="org.openxava.model.meta.MetaProperty" %> <% String propertyKey = request.getParameter("propertyKey"); // 1 MetaProperty p = (MetaProperty) request.getAttribute(propertyKey); // 2 String fvalue = (String) request.getAttribute(propertyKey + ".fvalue"); // 3 String align = p.isNumber()?"right":"left"; // 4 boolean editable="true".equals(request.getParameter("editable")); // 5 String disabled=editable?"":"disabled"; // 5 String script = request.getParameter("script"); // 6 boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel(); if (editable || !label) { // 5 %> <input id="<%=propertyKey%>" name="<%=propertyKey%>" class=editor <!-- 1 --> type="text" tabindex="1" <!-- 7 --> title="<%=p.getDescription(request)%>" align='<%=align%>' <!-- 4 --> maxlength="<%=p.getSize()%>" size="<%=p.getSize()%>" value="<%=fvalue%>" <!-- 3 --> <%=disabled%> <!-- 5 --> <%=script%> <!-- 6 --> /> <% } else { %> <%=fvalue%> <% } %> <% if (!editable) { %> <input type="hidden" name="<%=propertyKey%>" value="<%=fvalue%>"> <% } %>Un editor JSP recibe un conjunto de parámetros y tiene accesos a atributos que le permiten configurarse adecuadamente para encajar bien en una vista OpenXava. En primer lugar vemos como cogemos propertyKey (1) que después usaremos como id HTML. A partir de ese id podemos acceder a la MetaProperty (2) (que contiene toda la meta información de la propiedad a editar). El atributo fvalue(3) contiene el valor ya formateado y listo para visualizar. Averiguamos también la alineación (4) y si es o no editable (5). También recibimos el trozo de script de javascript (6) que hemos de poner en el editor.
<editor url="textEditor.jsp"> <formatedor clase="org.openxava.formatters.UpperCaseFormatter"/> <para-tipo tipo="java.lang.String"/> </editor>Estaremos sobreescribiendo el comportamiento de OpenXava para las propiedades de tipo String, ahora todas las cadenas se visualizaran y aceptaran en mayúsculas. Podemos ver el código del formateador:
package org.openxava.formatters; import javax.servlet.http.*; /** * @author Javier Paniza */ public class UpperCaseFormatter implements IFormatter { // 1 public String format(HttpServletRequest request, Object string) { // 2 return string==null?"":string.toString().toUpperCase(); } public Object parse(HttpServletRequest request, String string) { // 3 return string==null?"":string.toString().toUpperCase(); } }Un formateador ha de implementar IFormatter (1) o IMetaPropertyFormatter (nuevo en v5.9) lo que lo obliga a tener un método format() (2) que convierte el valor de la propiedad que puede ser un objeto Java cualquiera en una cadena para ser visualizada en un documento HTML; y un método parse() (3) que convierte la cadena recibida de un submit del formulario HTML en un objeto Java listo para asignar a la propiedad.
@Stereotype("REGIONES") private String [] regiones;Entonces podemos añadir una entrada en el archivo tipo-estereotipo-defecto.xml como sigue:
<para estereotipo="REGIONES" tipo="String []"/>
Y definir nuestro editor en el editores.xml de nuestro proyecto:<editor url="editorRegiones.jsp"> <!-- 1 --> <propiedad nombre="cantidadRegiones" valor="3"/> <!-- 2 --> <formateador clase="org.openxava.formatters.MultipleValuesByPassFormatter"/> <!-- 3 --> <para-estereotipo estereotipo="REGIONES"/> </editor>editorRegiones.jsp (1) es el archivo JSP que dibuja nuestro editor. Podemos definir propiedades que serán enviada al JSP como parámetros del request (2). El formateador tiene que implementar IMultipleValuesFormatter, que es similar a IFormatter pero usa String [] en vez de String. En este caso usamos un formateador genérico que simplemente deja pasar el dato.
<%@ page import="java.util.Collection" %> <%@ page import="java.util.Collections" %> <%@ page import="java.util.Arrays" %> <%@ page import="org.openxava.util.Labels" %> <jsp:useBean id="style" class="org.openxava.web.style.Style" scope="request"/> <% String propertyKey = request.getParameter("propertyKey"); String [] fvalues = (String []) request.getAttribute(propertyKey + ".fvalue"); // (1) boolean editable="true".equals(request.getParameter("editable")); String disabled=editable?"":"disabled"; String script = request.getParameter("script"); boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel(); if (editable || !label) { String sregionsCount = request.getParameter("cantidadRegiones"); int regionsCount = sregionsCount == null?5:Integer.parseInt(sregionsCount); Collection regions = fvalues==null?Collections.EMPTY_LIST:Arrays.asList(fvalues); %> <select id="<%=propertyKey%>" name="<%=propertyKey%>" multiple="multiple" class=<%=style.getEditor()%> <%=disabled%> <%=script%>> <% for (int i=1; i<regionsCount+1; i++) { String selected = regions.contains(Integer.toString(i))?"selected":""; %> <option value="<%=i%>" <%=selected%>> <%=Labels.get("regions." + i, request.getLocale())%> </option> <% } %> </select> <% } else { for (int i=0; i<fvalues.length; i++) { %> <%=Labels.get("regions." + fvalues[i], request.getLocale())%> <% } } %> <% if (!editable) { for (int i=0; i<fvalues.length; i++) { %> <input type="hidden" name="<%=propertyKey%>" value="<%=fvalues[i]%>"> <% } } %>Como se puede ver es como definir un editor para un valor simple, la principal diferencia es que el valor formateado (1) es un array de cadenas (String []) y no una cadena simple (String).
<%@ page import="java.util.Collection" %> <%@ page import="java.util.Collections" %> <%@ page import="java.util.Arrays" %> <%@ page import="org.openxava.util.Labels" %> <jsp:useBean id="style" class="org.openxava.web.style.Style" scope="request"/> <% String propertyKey = request.getParameter("propertyKey"); String [] fvalues = (String []) request.getAttribute(propertyKey + ".fvalue"); boolean editable="true".equals(request.getParameter("editable")); String disabled=editable?"":"disabled"; String script = request.getParameter("script"); boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel(); if (editable || !label) { String sregionsCount = request.getParameter("cantidadRegiones"); int regionsCount = sregionsCount == null?5:Integer.parseInt(sregionsCount); Collection regions = fvalues==null?Collections.EMPTY_LIST:Arrays.asList(fvalues); for (int i=1; i<regionsCount+1; i++) { String checked = regions.contains(Integer.toString(i))?"checked":""; %> <input name="<%=propertyKey%>" type="checkbox" class="<%=style.getEditor()%>" tabindex="1" value="<%=i%>" <%=checked%> <%=disabled%> <%=script%> /> <%=Labels.get("regions." + i, request.getLocale())%> <% } } else { for (int i=0; i<fvalues.length; i++) { %> <%=Labels.get("regions." + fvalues[i], request.getLocale())%> <% } } %> <% if (!editable) { for (int i=0; i<fvalues.length; i++) { %> <input type="hidden" name="<%=propertyKey%>" value="<%=fvalues[i]%>"> <% } } %>
<editor url="colorEditor.jsp"> <para-referencia modelo="Color"/> </editor>Con este código estamos diciendo que cualquier referencia a la entidad Color se tiene que visualizar usando colorEditor.jsp (para usar un editor solo para una referencia concreta en una entidad concreta véase la sección Escoger un editor del capítulo sobre Vista).
<%@page import="java.util.Iterator"%>
<%@page import="org.openxava.test.model.Color"%>
<%
String propertyKey = request.getParameter("propertyKey"); // Id de la propiedad clave de la referencia (1)
Object value = request.getAttribute(propertyKey + ".value"); // Podemos usar propertyKey + ".value" (2)
if (value == null) value = new Integer(0);
%>
<%
Iterator it = Color.findAll().iterator();
for (int c=0; it.hasNext() && c < 3; c++) {
Color color = (Color) it.next();
String checked = value.equals(color.getNumber())?"checked='checked'":"";
%>
<input name="<%=propertyKey%>" value="<%=color.getNumber()%>" type="radio" <%=checked%> <!-- (3) -->
tabindex="1"/>
<span>
<font color="#<%=color.getHexValue()%>"><b><%=color.getName()%></b></font>
</span>
<%
}
%>
<editor nombre="MiReferencia" url="miReferenciaEditor.jsp" enmarcable="true" compuesto="true"> <para-referencias/> </editor>Ya que hemos marcado el editor con <para-referencias/> ahora todas las referencias de nuestra aplicación se visualizarán usando nuestro miReferenciaEditor.jsp. Esta es una forma sencilla de personalizar el comportamiento del generador de interfaz de usuario de OpenXava.
<editor url="comentariosBlogEditor.jsp"> <para-coleccion modelo="ComentarioBlog"/> </editor>Con el código de arriba estamos diciendo que cualquier colección de entidades ComentarioBlog tiene que ser visualizada y editada usando comentariosBlogEditor.jsp (para usar un editor solo para una colección concreta en una entidad concreta ver la sección Escoger un editor en el capítulo sobre Vista).
<jsp:include page="collectionEditor.jsp"> <jsp:param name="listEditor" value="comentariosBlogListEditor.jsp"/> </jsp:include>Esta es una forma habitual de crear un editor para colecciones. Aquí llamamos a collectionEditor.jsp (el editor por defecto de OpenXava para colecciones) enviando como argumento para listEditor un JSP que contiene el editor para parte de la lista. De esta forma tenemos gratis todas las acciones y comportamiento por defecto de las colecciones, por tanto solo hemos de preocuparnos por dibujar la lista.
<%@ include file="../imports.jsp"%> <%@page import="org.openxava.view.View"%> <%@page import="org.openxava.model.MapFacade"%> <%@page import="org.openxava.test.model.Blog"%> <%@page import="org.openxava.test.model.BlogComment"%> <%@page import="java.util.Iterator"%> <%@page import="java.util.Map"%> <%@page import="java.text.DateFormat"%> <%@page import="org.openxava.util.Locales"%> <%@page import="org.openxava.util.Is"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String viewObject = request.getParameter("viewObject"); // Id para acceder al objeto view de la colección View collectionView = (View) context.get(request, viewObject); // Obtenemos el objeto view de la colección mediante context View rootView = collectionView.getRoot(); // En este caso usamos la vista raiz, la vista de Blog Map key = rootView.getKeyValues(); if (Is.empty(key)) { %> No hay comentarios <% } else { // Si la clave tiene valor dibujamos la colección de comentarios Blog blog = (Blog) MapFacade.findEntity("Blog", key); String action = request.getParameter("rowAction"); // rowAction es la acción para editar o visualizar cada elemento String actionArgv = ",viewObject=" + viewObject; %> Estos son los comentarios<br/> <% DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locales.getCurrent()); int f=0; for (Iterator it = blog.getComentarios().iterator(); it.hasNext(); f++) { ComentarioBlog comentario = (ComentarioBlog) it.next(); %> <i><b><big>Comentario del <%=df.format(comentario.getFecha())%></big></b></i> <xava:action action='<%=action%>' argv='<%="row=" + f + actionArgv%>'/> <p> <i><%=comentario.getCuerpo()%></i> </p> <hr/> <% } } %>Este editor dibuja los comentarios del blog como un texto simple con una cabecera con la fecha.
<%@page import="org.openxava.view.View"%> <%@page import="org.openxava.model.MapFacade"%> <%@page import="org.openxava.test.model.Carrier"%> <%@page import="java.util.Iterator"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String viewObject = request.getParameter("viewObject"); // viewObject es el id del objeto view del padre View view = (View) context.get(request, viewObject); // view es el objeto view de Transportista, el padre de la colección Transportista transportista = (Transportista) MapFacade.findEntity("Transportista", view.getKeyValues()); %> Los compañeros de <%=transportista.getNombre()%> son:<br> <ul> <% for (Iterator it = transportista.getCompaneros().iterator(); it.hasNext(); ) { Transportista companero = (Transportista) it.next(); %> <li><%=companero.getNombre()%></li> <% } %> </ul>En este caso escribimos el código para dibujar la colección completamente, si queremos tener algunas acciones para trabajar con la colección tenemos que ponerlas nosotros mismos. ¡Ojo!, porque aquí viewObject es la vista del objeto que contiene la colección, no de la colección en sí.
<editor nombre="MiColeccion" url="miColeccionEditor.jsp"> <para-colecciones/> </editor> <editor nombre="MiColeccionElementos" url="miColeccionElementosEditor.jsp"> <para-colecciones-elementos/> <!-- Nuevo en v5.0 --> </editor>Ahora todas las colecciones @OneToMany/@ManyToMany en nuestra aplicación se visualizan usando nuestro miColeccionEditor.jsp y las @ElementCollection usando nuestro miColeccionElementosEditor.jsp.
<editor url="empleadoCorporativoListEditor.jsp"> <para-tab modelo="EmpleadoCorporativo"/> </editor>Con el código de arriba estamos diciendo que todos los tabs (es decir todas la listas) para la entidad EmpleadoCorporativo tienen que ser editados y visualizados usando empleadoCorporativoListEditor.jsp (para usar un editor sólo para un tab concreto de una entidad ver la sección Escogiendo un editor).
<%@ include file="../imports.jsp"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String tabObject = request.getParameter("tabObject"); tabObject = (tabObject == null || tabObject.equals(""))?"xava_tab":tabObject; org.openxava.tab.Tab tab = (org.openxava.tab.Tab) context.get(request, tabObject); String condition = tab.getBaseCondition()==null?"":tab.getBaseCondition(); String all = condition.equals("")?"selected":""; String low = condition.contains("<=")?"selected":""; String high = condition.contains(">")?"selected":""; String action="openxava.executeAction('OpenXavaTest', 'EmpleadoCorporativo'," + "false, false, 'EmpleadoCorporativo.filtrar', 'segmento='+this.value)"; %> <select name="<xava:id name='escogerSegmento'/>" onchange= "<%=action%>"> <option value="all" <%=todos%>>Todos los empleados</option> <option value="low" <%=bajo%>>Empleados con salario bajo</option> <option value="high" <%=alto%>>Empleados con salario alto</option> </select> <jsp:include page="listEditor.jsp"/>Un detalle importante es que este editor incluye listEditor.jsp al final. listEditor.jsp es el editor por defecto para modo lista, por tanto en este caso simplemente estamos refinando la lista estándar añadiendo un combo para escoger un filtro personalizado. Sin embargo, podemos crear nuestro propio editor para lista desde cero, por ejemplo, el siguiente editor, fichasClienteListEditor.jsp, muestra la lista de clientes como una fila de fichas:
<%@ include file="../imports.jsp"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String collection = request.getParameter("collection"); String id = "list"; String collectionArgv = ""; String prefix = ""; String tabObject = request.getParameter("tabObject"); tabObject = (tabObject == null || tabObject.equals(""))?"xava_tab":tabObject; if (collection != null && !collection.equals("")) { id = collection; collectionArgv=",collection="+collection; prefix = tabObject + "_"; } org.openxava.tab.Tab tab = (org.openxava.tab.Tab) context.get(request, tabObject); org.openxava.tab.impl.IXTableModel model = tab.getTableModel(); for (int r=tab.getInitialIndex(); r<model.getRowCount() && r < tab.getFinalIndex(); r++) { %> <xava:link action="List.viewDetail"><div class="ficha-cliente"> <h4><%=model.getValueAt(r, 1)%>(<%=model.getValueAt(r, 0)%>)</h4> <%=model.getValueAt(r, 2)%><br/> <%=model.getValueAt(r, 3)%> (<%=model.getValueAt(r, 4)%>) </div></xava:link> <% } %>Para este editor usamos una clase CSS, ficha-cliente (el estilo en línea no está permitido desde v7.1), pon esta clase CSS en un archivo fichasClienteListEditor.css dentro de la carpeta src/main/webapp/xava/editors/style (web/xava/editors/style en v6 o anterior) de tu proyecto, puede que necesites crear la carpeta style la primera vez:
.ficha-cliente {
border: 2px solid rgb(130, 143, 149);
display: inline-block;
padding: 10px;
margin-bottom: 10px;
}
<editor nombre="MiLista" url="miListaEditor.jsp"> <para-tabs/> </editor>Como hemos marcado el editor con <for-tabs/> ahora todos los tabs de nuestra aplicación se visualizaran usando nuestro miListaEditor.jsp. Esta es una forma sencilla de personalizar el comportamiento del generador de interfaz gráfica de OpenXava.
<editor name="List" url="listEditor.jsp" icon="table-large"> <for-tabs/> </editor> <editor name="Charts" url="chartsEditor.jsp" selectable-items="false" icon="chart-line" init-action="Chart.init" release-action="Chart.release"> <for-tabs/> </editor>Y esto en editores.xml de tu proyecto:
<editor nombre="MiFicha" url="miFichaEditor.jsp" icono="view-module"> <para-tabs/> </editor>Tu usuario tendrá tres formatos para escoger en la lista:
package com.tuempresa.facturacion.anotaciones;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface Colorido {
String color() default "black";
}
@Column(length=40) @Required
@Colorido(color = "green")
String nombre;
<editor nombre="Colorido" url="coloridoEditor.jsp">
<propiedad nombre="fondo" valor="yellow"/>
<para-anotacion anotacion="com.tuempresa.facturacion.anotaciones.Colorido"/>
</editor>
<%
String fondo = request.getParameter("fondo");
String color = request.getParameter("color");
%>
<span class="colorido-color-<%=color%> colorido-fondo-<%=background%>">
<jsp:include page="textEditor.jsp"/>
</span>
.colorido-color-black input { color: black; }
.colorido-fondo-black input { background: black; }
.colorido-color-white input{ color: white; }
.colorido-fondo-white input{ background: white; }
.colorido-color-red input{ color: red; }
.colorido-fondo-red input{ background: red; }
.colorido-color-green input{ color: green; }
.colorido-fondo-green input{ background: green; }
.colorido-color-blue input{ color: blue; }
.colorido-fondo-blue input{ background: blue; }
.colorido-color-yellow input{ color: yellow; }
.colorido-fondo-yellow input{ background: yellow; }
.colorido-color-orange input{ color: orange; }
.colorido-fondo-orange input{ background: orange; }
.colorido-color-purple input{ color: purple; }
.colorido-fondo-purple input{ background: purple; }
.colorido-color-gray input{ color: gray; }
.colorido-fondo-gray input{ background: gray; }
<input ... onclick="f()"/> <!-- NO PERMITIDO DESDE V7.1-->
En su lugar has de asociar los eventos desde el código en tus archivos JS.
Para tu código JavaScript crea un archivo llamado miEditor.js (o
cualquier otro nombre que quieras), y ponlo en la carpeta src/main/webapp/xava/editors/js
(web/xava/editors/js en v6 o anteriores). openxava.addEditorInitFunction(function() { /* Aquí tu código de inicialización para tu editor. Es decir, las cosas que normalmente pondrías en el event onload de JavaScript o $(function() { ... }) de jQuery */ ... });Vemos como usamos openxava.addEditorInitFunction() para registrar una función de inicialización. El evento JavaScript onload o el evento ready() de jQuery no funciona, porque no se produce carga de página, en vez de eso el editor se genera en el servidor, se carga vía AJAX y se inserta en la página que ya se estaba visualizando.
openxava.addEditorDestroyFunction(function() { // Nuevo en v4.8.1 /* Aquí el código de destrucción de tu editor. Esto es para liberar los recursos obtenidos por el editor. */ ... });
A partir de v7.1 puedes definir una función a ejecutar
antes de cada llamada AJAX de OpenXava, ponla en tu miEditor.js:
openxava.addEditorPreRequestFunction(function() { // Nuevo en v7.1 /* Aquí el código a ejecutar para tu editor antes de cada llamada AJAX de OpenXava. */ ... });
Por ejemplo, si quieres mostrar un diálogo de JavaScript con un mensaje cuando el usuario pulse en un botón de tu editor, y tienes este código en tu miEditor.jsp:
<input class="mi-editor" type="button" value="Di hola"/>
openxava.addEditorInitFunction(function() {
$(".mi-editor").click(function() {
alert("Hola");
});
});
@Stereotype("FAMILY") private int familyNumber; @Stereotype("SUBFAMILY") private int subfamilyNumber;Y en nuestro editores.xml ponemos:
<editor url="descriptionsEditor.jsp"> <!-- 10 --> <propiedad nombre="modelo" valor="Familia"/> <!-- 1 --> <propiedad nombre="propiedadClave" valor="codigo"/> <!-- 2 --> <propiedad nombre="propiedadDescripcion" valor="descripcion"/> <!-- 3 --> <propiedad nombre="ordenadoPorClave" valor="true"/> <!-- 4 --> <propiedad nombre="readOnlyAsLabel" valor="true"/> <!-- 5 --> <para-estereotipo estereotipo="FAMILIA"/> <!-- 11 --> </editor> <!-- Es posible especificar dependencias de estereotipos o propiedades --> <editor url="descriptionsEditor.jsp" <!-- 10 --> depende-de-estereotipos="FAMILIA"> <!-- 12 --> <!-- <editor url="descriptionsEditor.jsp" depende-de-propiedades="codigoFamilia"> <!-- 13 --> --> <propiedad nombre="modelo" valor="Subfamilia"/> <!-- 1 --> <propiedad nombre="propiedadClave" valor="codigo"/> <!-- 2 --> <propiedad nombre="propiedadesDescripcion" valor="codigo, descripcion"/> <!-- 3 --> <propiedad nombre="condicion" value="${codigoFamilia} = ?"/> <!-- 6 --> <propiedad nombre="estereotiposValoresParametros" valor="FAMILIA"/> <!-- 7 --> <!-- <propiedad nombre="propiedadesValoresParametros" valor="codigoFamilia"/> <!-- 8 --> --> <propiedad nombre="formateadorDescripciones" <!-- 9 --> valor="org.openxava.test.formatters.FormateadorDescripcionesFamilia"/> <para-estereotipo estereotipo="SUBFAMILIA"/> <!-- 11 --> </editor>Al visualizar una vista con estas dos propiedades codigoFamilia y codigoSubfamilia sacará un combo para cada una de ellas, el de familias con todas las familias disponible y el de subfamilias estará vacío y al escoger una familia se rellenará con sus subfamilias correspondientes.
<modulo nombre="ComercialJSP" carpeta="facturacion.variaciones"> <modelo nombre="Comercial"/> <vista nombre="ParaJSPPropio"/> <!-- 1 --> <vista-web url="jsp-propios/comercial.jsp"/> <!-- 2 --> <controlador nombre="Typical"/> </modulo>Si usamos vista-web (2) al definir el módulo, OpenXava usa nuestro JSP para dibujar el detalle, en vez de usar la vista generada automáticamente. Opcionalmente podemos definir una vista OpenXava con vista (1), esta vista es usada para saber que eventos lanzar y que propiedades llenar, si no se especifica se usa la vista por defecto de la entidad; aunque es aconsejable crear una vista OpenXava explícita para nuestra vista JSP, de esta manera podemos controlar los eventos, las propiedades a rellenar, el orden del foco, etc explicitamente. Podemos poner nuestro JSP dentro de la carpeta src/main/webapp/custom-jsp/jsp-propios (u otra de nuestra elección) de nuestro proyecto (web en lugar de src/main/webapp para versiones anteriores a v7.0), y este JSP puede ser así:
<%@ include file="../xava/imports.jsp"%> <table> <tr> <td>Código: </td> <td> <xava:editor property="codigo"/> </td> </tr> <tr> <td>Nombre: </td> <td> <xava:editor property="nombre"/> </td> </tr> <tr> <td>Nivel: </td> <td> <xava:editor property="nivel.id"/> <xava:editor property="nivel.descripcion"/> </td> </tr> </table>Somos libres de crear el archivo JSP como queramos, pero puede ser práctico usar las taglibs de OpenXava, en este caso, por ejemplo, se usa <xava:editor/>, esto dibuja un editor apto para la propiedad indicada, además añade el JavaScript necesario para lanzar los eventos. Si usamos <xava:editor/>, podemos manejar la información visualizada usando el objeto xava_view (del tipo org.openxava.view.View), por lo tanto todos los controladores estándar de OpenXava (CRUD incluido) funcionan.
<xava:editor property="nombrePropiedad" <!-- 1 --> editable="true|false" <!-- 2 Nuevo en v2.0.1 --> throwPropertyChanged="true|false" <!-- 3 Nuevo en v2.0.1 --> />
<xava:action action="controlador.accion" argv="argv"/>
El atributo action indica la acción a ejecutar, y el atributo argv
(opcional) nos permite establecer valores a algunas propiedades de la
acción antes de ejecutarla. Un ejemplo:<xava:action action="CRUD.save" argv="resetAfter=true"/>
Cuando el usuario pulse en la acción se ejecutará CRUD.save,
antes pone a true la propiedad resetAfter de la acción.<xava:action action=""/>
En este caso la marca (tag) no tiene efecto y no se produce error. Esta
característica puede ser útil cuando el nombre de la acción lo obtenemos
dinámicamente (es decir action=”<%=micodigo()%>”), y el
valor pueda estar vacío en ciertos casos.<xava:message key="clave_mensaje" param="parametroMensaje" intParam="paramMensaje"/>
El mensaje es buscado primero en los archivos de recursos de nuestro
proyecto (miproyecto/src/main/resources/i18n/miproyecto-messages_es.properties
para v7 o superior, y MiProyecto/i18n/MensajesMiProyecto.properties
para v6 o anterior) y si no se encuentra ahí es buscado en los mensajes
por defecto de OpenXava (openxava/src/main/resources/i18n/Messages_en.properties
para v7 o superior, y OpenXava/i18n/Messages.properties
para v6 o anterior).<xava:message key="cantidad_lista" intParam="<%=cantidadTotal%>"/>
<xava:label key="nombreMiembro"/>
El mensaje es buscado primero en los archivos de etiquetas de nuestro
proyecto (miproyecto/src/main/resources/i18n/miproyecto-labels_es.properties
para v7 o superior, y MiProyecto/i18n/EtiquetasMiProyecto.properties
para v6 o anterior) y si no se encuentra ahí es buscado en los mensajes
por defecto de OpenXava (openxava/src/main/resources/i18n/Labels_en.properties
para v7 o superior, y OpenXava/i18n/Labels.properties
para v6 o anterior).<tr> <td>Number: </td><td> <xava:editor property="number"/> </td> </tr>Puedes escribir esto:
<tr> <td><xava:label key="number"/>: </td><td> <xava:editor property="number"/> </td> </tr>Y así tener la etiqueta traducida.
<xava:descriptionsList reference="nombreReferencia" <!-- 1 -->
readOnlyAsLabel="true|false" <!-- 2 Nuevo en v6.0.1 -->
/>
<tr> <td>Nivel: </td> <td> <xava:descriptionsList reference="nivel"/> </td> </tr>En este caso nivel es una referencia al modelo actual (por ejemplo Comercial). Un combo es mostrado con todos los niveles disponibles.
<%@include file="../xava/imports.jsp"%>
...
<script type="text/javascript" <xava:nonce/>>
var button = document.getElementById('welcome_go_signin');
button.onclick = function () { window.location='m/SignIn'; }
</script>
Propiedad |
Descripción |
Valor por defecto |
Correo Electronico |
||
emailAsUserNameInPortal (quitado a partir de v7.0) | false |
|
smtpHost |
Servidor de correo SMTP |
|
smtpHostTrusted (nuevo en v4.7) |
Si es true se puede utilizar un servidor de correos
SMTP con el certificado vencido |
false |
smtpPort |
Puerto para envio de correos |
|
smtpUserId |
Usuario para conectar al servidor SMTP |
|
smtpUserPassword |
Contraseña del usuario para servicios de correo |
|
smtpStartTLSEnable (nuevo en v5.6) |
Si es true activa el uso de la orden STARTTLS (si lo
soporta el servidor) para cambiar la conexión a una conexión
protegida con TLS antes de usar cualquier orden de identificación. |
false |
smtpFromEmail (nuevo en v6.2) |
Valor para el campo from del mensaje. Úsalo si necesitas
un valor diferente para el id de usuario y para el campo from
(útil en entornos del tipo AWS SES). |
El valor de smtpUserId |
Persistencia |
||
defaultPersistenceUnit |
Unidad de persistencia predeterminada |
default |
jpaCodeInPOJOs (quitado a partir de v5.6) |
Depends on persistence provider |
|
mapFacadeAsEJB |
false |
|
mapFacadeAutoCommit |
false |
|
persistenceProviderClass (quitado a partir de v5.6) |
Clase encargada de manejar la persistencia de datos |
org.openxava.model.impl.JPAPersistenceProvider |
Etiquetas, Mensajes y Localización |
||
i18nWarnings |
false |
|
portletLocales (quitado a partir de v7.0) | Si no se especifica se usan los locales incluidos en la carpeta
i18n |
bg, ca, de, en, es, fr, in, it, ja, ko, nl, pl, pt, ru, sv, zh |
Aplicación y Controladores |
||
defaultLabelFormat |
Possibles values for defaultLabelFormat are: NORMAL, SMALL
and NO_LABEL |
NORMAL |
defaultLabelStyle |
Se han definido: bold-label, italic-label, además de que puede
definir sus propios estilos |
|
defaultModeController (nuevo en v4m5) |
Los valores posibles para defaultModeController son: Mode,
DetailList, DetailOnly, ListOnly and SplitOnly |
Mode |
duplicateComponentWarnings |
Cuando se encuentran componentes con nombres duplicados se
generan mensajes de advertencia |
true |
failOnAnnotationMisuse |
Lanza un error si algún miembro (propiedades, referencias o
colecciones) tienen anotaciones que no les son aplicables |
true |
generateDefaultModules |
Si es true no es requerido definir los módulos en
application.xml / applicacion.xml. OX se encarga de generarlos
automaticamente |
true |
Estilos |
||
liferay6StyleClass (nuevo en v4m6, quitado a
partir de v7.0) |
Estilo compatible con liferay 6 |
org.openxava.web.style.Liferay6Style |
liferay51StyleClass (quitado a partir de v7.0) | Estilo compatible con liferay 5.1 |
org.openxava.web.style.Liferay51Style |
liferay41StyleClass (quitado a partir de v7.0) | Estilo compatible con liferay 4.1 |
org.openxava.web.style.Liferay41Style |
liferay43StyleClass (quitado a partir de v7.0) | Estilo compatible con liferay 4.3 |
org.openxava.web.style.Liferay43Style |
webSpherePortal61StyleClass (quitado a partir de v7.0) | Estilo compatible WebSphere Portal 6.1 |
org.openxava.web.style.WebSpherePortal61Style |
styleClass |
Maneja la asignación de atributos class para los
elementos desplegables. |
org.openxava.web.style.XavaStyle (desde v6.0) org.openxava.web.style.Liferay51Style (hasta v5.9.1) |
styleCSS |
URL del archivo CSS que provee las caracteristicas de la
interfase visual. |
terra.css (desde v6.0) liferay51/css/everything_unpacked.css (hasta v5.9.1) |
themes (nuevo en v6.3) |
Lista de archivos CSS separados por coma de los estilos
disponibles para ser elegidos como temas por el usuario. Si el
valor está vacío el selector de temas no está disponible para el
usuario. |
Vacío |
Vistas |
||
alignedByColumns (nuevo en v4.7.1) |
Si es true las propiedades de la vista son desplegadas
alineadas por columnas. Sólo funciona en las implementaciones por
defecto de layoutParser & layoutPainter. Provoca que las todas
las vistas se comporten como si tuviesen # al inicio |
false |
buttonsForNoImageActions |
Si es true, cuando una acción no tiene imagen asociada
muestra un botón. Si es false entonces muestra un
hipervínculo |
false |
layoutParser (nuevo en v4.5, hasta v6.0.2) |
Nombre del interpretador de despliegue de vistas. Ha de
implementar org.openxava.web.layout.ILayoutParser |
Hasta v5.4.1: org.openxava.web.layout.impl.DefaultLayoutParser A partir de v5.5: null (por tanto usa JSP) |
layoutPainter (nuevo en v4.5, hasta v6.0.2) |
Nombre de la clase encargada de dibujar las vistas. Ha de
implementar org.openxava.web.layout.ILayoutPainter |
Hasta v5.4.1: org.openxava.web.layout.impl.DefaultLayoutPainter A partir de v5.5: null (por tanto usa JSP) |
maxSizeForTextEditor |
Limita el tamaño del campo de entrada para propiedades que
representen textos largos |
100 |
messagesOnTop (nuevo en v4.5. hasta v5.7.1) |
Si es true los errores, advertencias y mensajes son
mostrados en la parte superior de la página, si es false
son mostrados al pie de la página. A partir de v5.8 se puede user
CSS para poner los mensajes abajo. |
true |
readOnlyAsLabel |
false |
|
showIconForViewReadOnly (nuevo en v4.6) |
||
showLabelsForToolBarActions (nuevo en v4m6) |
Si es false, la barra de botones no despliega lo nombre de
las acciones, sólo las imágenes |
true |
useIconsInsteadOfImages (nuevo en v5.4) |
Cuando se especifique un icono y una imagen para una acción, se
usará el icono |
true |
flowLayout (nuevo en v5.7) |
Si es true la disposición de los campos se ajusta al
tamaño de la página, ignorando los , ; # de @View |
false |
showDefaultActionInBottom (nuevo en v5.8) |
Si es true la acción por defecto aparece como la
primera acción abajo, incluso si ya está en la barra de botones
superior |
true |
Listas y Colecciones |
||
addColumnsPageRowCount (hasta v5.1.1) |
Limita el numero de propiedades seleccionables para ser
adicionadas a las columnas de las listas o propiedades |
100 |
customizeList (nuevo en v4m5) |
Si es false, no se permite personalizar las columnas
de la lista |
true |
detailOnBottomInCollections |
false |
|
ignoreAccentsForStringArgumentsInConditions (nuevo en v4m6) |
Si es true Ignora las acentuaciones en las condiciones
de lista y colecciones |
false |
pageRowCount |
Default number of objects to show in lists and collections |
10 |
resizeColumns (nuevo en v4m5) |
Si es false, No se permite cambiar el tamaño de las
columnas |
true hasta v5.9.1, false a partir de v6.0 |
saveAndStayForCollections (nuevo en v4m6) |
Si es false, el boton grabar y continuar no
es mostrado cuando adicionan elementos a collecciones |
true |
showCountInList |
true |
|
showIconForViewReadOnly |
true |
|
showFilterByDefaultInList |
Si es true, la fila de filtrar se muestra inicialmente
en las listas, El usuario siempre tiene la opción de mostrar /
ocultar la fila de filtrado |
true |
showFilterByDefaultInCollections (quitada a partir de v6.0) |
Si es true, la fila de filtrar se muestra inicialmente en las colecciones, El usuario siempre tiene la opción de mostrar / ocultar la fila de filtrado |
true |
summationInList (nuevo en v4.3) |
Si es true Se muestra una fila de totales al final de
la lista, bajo los campos numericos. El usuario puede manualmente
encender o apagar los totales para cada columna |
true |
tabAsEJB |
false |
|
toUpperForStringArgumentsInConditions |
Si es true se convierten a mayusculas los argumentos
de busqueda en las listas y colecciones. Aunque esto permite las
busquedas de datos independientemente de que esten en mayusculas o
minusculas, puede producir bajos rendimientos con algunos
manejadores de base de datos |
true |
filterOnChange (nuevo en v4.8) |
El filtrado se realiza automáticamente al seleccionar una opción
de un combo, sin pulsar en el botón de filtrar |
true |
Ayuda |
||
helpAvailable (nuevo en v5.6) |
Si es true un icono para acceder a la ayuda se muestra
en el módulo |
false since v6.0, true until v5.9.1 |
helpInNewWindow (nuevo en v4m5) |
Si es true la página de ayuda se muestra en una nueva
ventana, si es false, la página de ayuda es abierta en
la ventana actual |
true |
helpPrefix (nuevo en v4m5) |
Prefijo para la generación del URL de ayuda |
|
helpSuffix (nuevo en v4m5) |
Sufijo para la generación del URL de ayuda |
|
Estereotipo FILE/ARCHIVO |
||
filePersistorClass |
Clase encargada de almacenar los archivos adjuntos |
org.openxava.web.editors.FileSystemPersistor |
filesPath |
Directorio de almacenamiento de los archivos, en caso no se use
base de datos. |
|
Estereotipo COORDENADAS/COORDINATES (nuevo
en v6.6) |
||
mapsTileProvider |
La URL del proveedor de imágenes de mapa (tile provider). Puedes usar un tile provider de OpenTopoMap (https://b.tile.opentopomap.org/{z}/{x}/{y}.png), MapBox (https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=YOUR_ACCESS_TOKEN), Stamen (http://tile.stamen.com/toner/{z}/{x}/{y}.png), OpenStreeMap (https://tile.openstreetmap.org/{z}/{x}/{y}.png) o Thunderforest (https://tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png?apikey=YOUR_API_KEY), entre otros. Te cuidado con cumplir con los términos de servicio del proveedor correspondiente. | https://b.tile.opentopomap.org/{z}/{x}/{y}.png |
mapsAttribution |
Texto de atribución a mostrar en una esquina del mapa. Depende
del proveedor que uses. Asegurate de usar la atribución correcta. |
Map data © OpenStreetMap contributors, Imagery © OpenTopoMap (CC-BY-SA) |
mapsTileSize |
Ancho y alto de la imagen en la rejilla. |
256 |
mapsZoomOffset |
El número de zoom usado en la URL será ajustado según este
valor. |
0 |
Reportes |
||
reportParametersProviderClass |
Clase para obtener los parametros para los informes. Tiene que
implementar IReportParametersProvider o
IRequestReportParametersProvider. |
org.openxava.util.DefaultReportParametersProvider |
Content Security Policy (CSP) |
||
trustedHostsForImages (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar
como origen para las imágenes. Se añade a img-src de la Política
de Seguridad de Contenido (Content Security Policy, CSP). Puedes
utilizar cualquier <host-source>
como se explica en la documentación de CSP. |
|
trustedHostsForScripts (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para los scripts. Se añade a script-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. | |
trustedHostsForStyles (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para los archivos CSS. Se añade a style-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. | |
trustedHostsForFrames (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para los frames e iframes. Se añade a frame-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. | |
turnOffWebSecurity (nuevo en v7.2) | Si es true las cabeceras de Content Security Policy no se envían. Esto permitiría la ejecución de código malicioso en la página web de la aplicación, por eso es aconsejable utilizar las propiedades de arriba (las trustedHostForXXXX) antes de poner turnOffWebSecurity a true. | false |
Miscelánea |
||
csvEncoding (nuevo en v4.2.1) |
Porque es imposible obtener la codificación del cliente, que es
usada por Excel al abrir el archivo. UTF-8, ISO-8859-1 |
|
csvSeparator |
; |
|
hibernateJavaLoggingLevel |
Nivel para la bitácora de Hibernate. Los valores pueden ser:
SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL, OFF |
INFO |
javaLoggingLevel |
Nivel para la bitácora de Java. Los valores válidos son: SEVERE,
WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL, OFF |
INFO |
componentParsersClasses (nuevo en v5.6) |
Lista de clases separadas por comas para analizar los
componentes, tienen que implementar org.openxava.component.parse.IComponentParser |
org.openxava.component.parse.XMLComponentParser,
org.openxava.component.parse.AnnotatedClassParser |
connectionRefinerClass (nuevo en v5.6) |
Clase para crear un org.openxava.util.IConnectionRefiner para
refinar las conexiones JDBC justo después de obtenerlas de la
fuente de datos y antes de usarlas. |
|
accessTrackerProvidersClasses
(nuevo
en v5.9) |
Lista
de clases separadas por comas usadas para monitorear cada cambio
o acceso de lectura hecho por los usuarios a los datos. Las
clases tienen que implementar
org.openxava.util.IAccessTrackerProvider. Ya hay algunos
proveedores incluidos en OpenXava como org.openxava.util.EmailNotificationsAccessTrackerProvider
y org.openxava.util.LogAccessTrackerProvider. |
|
enterMovesToNextField (nuevo en v6.4) |
Si true la tecla INTRO (ENTER) mueve el foco al
siguiente campo, como la tecla TAB, en lugar de aceptar el
formulario. |
false |
applicationPort (nuevo en v6.4.2) | El puerto usado por el lanzador de la aplicación (la clase _Run_TuAplicacion). | 8080 |
defaultDescriptionPropertiesValueForDescriptionsList (nuevo en v7.1) | Nombres de las propiedades a mostrar en el combo de un @DescriptionsList cuando el atributo descriptionProperties se omite. | descripcion, description, nombre, name |