Na implementação do padrão de interface, quando o item de menu 'Livro' é selecionado uma ação (criar) em Ação de Cadastro do Livro é

estabelecida.

Código Tela de Cadastro de Livros

Implementação Tela de Cadastro de Livros

<menu:subMenu labelKey="submenu.cadastro.simples">
<menu:subMenuItem labelKey="submenuitem.cadastro.simples.livro">
<crypto:encryptUrl value="/livro/cadastro.do?actionType=criar"/>
</menu:subMenuItem>
</menu:subMenu>
menu.jsp

A operação criar de CadastroAction.java (conforme implementado) invoca indiretamente (via struts-config.xml) a operação carregar (também de CadastroAction.java) a partir de um Forward identificado pelo rótulo load (FWD_LOAD).

public ActionForward criar(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception {
reinicializar todas as propriedades do form
((DynaActionForm)form).initialize(mapping);

TODO carregar os dados necessários para a criação de um novo registro
return mapping.findForward(FWD_LOAD);
}

public ActionForward carregar(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception {
gêneros disponíveis para seleção
request.setAttribute("generos", this.getGeneros());

idiomas disponíveis para seleção
request.setAttribute("idiomas", this.getIdiomas());
retornar para a edição do cadastro
return mapping.findForward(FWD_EDIT);
}

private List getIdiomas(){
return Arrays.asList(
new String{"Portugues","Ingles","Espanhol","Outra"});
}

private List getGeneros(){
return Arrays.asList(new String
{"Auto Ajuda","Bibliografia","Comedia","Drama","Policial","Tecnico"});
}
CadastroAction.java

A operação carregar (em CadastroAction.java) cria duas listas de valores que serão utilizadas pelo contexto da aplicação para a interação

de cadastro de livros. A execução da ação 'carregar' também é responsável em iniciar, a partir de um Forward identificado pelo rótulo

edit (FWD_EDIT), a interface de cadastro (via struts-config.xml), conforme layout estabelecido em tiles-definitions.xml e Cadastro.jsp.

<definition name="livro.cadastroextends="layout.normal">
<put name="content" value="/jsp/livro/cadastro.jsp"/>
</definition>
tiles-definitions.xml

...
<!-- ####### Livro Actions ######## -->
<action path="/livro/cadastro"
type="gov.tjpr.inteface.client.livro.action.CadastroAction"
scope="request"
parameter="actionType"
name="livroCadastroForm"
input="livro.cadastro"
validate="false">
<!-- flag for indicating that resource security isn't required -->
<set-property property="checkPermission" value="false"/>
<forward name="load" path="/livro/cadastro.do?actionType=carregar"/>
<forward name="edit" path="livro.cadastro"/>
</action>
...
struts-config.xml

 

Pesquisa de chave estrangeira

Conforme estabelecido pelo Grupo de Discussão do Padrão de Interface, a tela de pesquisa de chave estrangeira foi implementada em uma

janela popup modal representada pela figura abaixo:
 



<tr>
<td class="label">
<label for="nomeAutor"><em>*</em>
<fmt:message key="livro.autor"/>:</label>
</td>
<fmt:message var="popupTitle" key="livro.autor.selection"/>
<crypto:encryptUrl value="/autor/pesquisaFilter.do" var="popupURL" />
<td>
<html:text property="nomeAutor" readonly="true" styleId="nomeAutor" size="40"/>
<a href="javascript:openDialog('${popupURL}','${popupTitle}',400,300);"
class="searchButton" title="${popupTitle}">
<span>${popupTitle}</span>
</a>
<a href="javascript:Form.Element.clear('idAutor');
Form.Element.clear('nomeAutor');void(0);"
class="eraseButton">
<span><fmt:message key="button.erase"/></span>
</a>
</td>
<html:hidden styleId="idAutor" property="idAutor"/><div id="nomeAutorDiv"></div>
</tr>

Uma ação executada no SearchButton especificado por Cadastro.jps estabelece um fluxo de navegação para a tela de pesquisa de chave

estrangeira a partir de /autor/pesquisaFilter.do configurado em struts-config.xml e tiles-definitions.xml.

Note que a definição das dimensões da janela modal é definida no momento do chamamento da janela. javascript:openDialog('${popupURL}','${popupTitle}',400,300);

<!-- ####### Autor Actions ######## -->
<action path="/autor/pesquisaFilter"
type="org.apache.struts.actions.ForwardAction"
scope="request"
parameter="autor.pesquisa"
name="autorPesquisaForm">
<!-- flag for indicating that resource security isn't required -->
<set-property property="checkPermission" value="false"/>
</action>

struts-config.xml

<!-- ############ Autor Pages ############ -->
<definition name="autor.pesquisa" extends="layout.popup">
<put name="content" value="/jsp/autor/pesquisa.jsp"/>
</definition>

tiles-definitions.xml

O arquivo ApplicationResources.properties estabelece um mecanismo padronizado de utilização de textos para labels, botões, mensagens,

etc. Em muitos momentos os 'rótulos' estabelecidos em ApplicationResources.properties são utilizados, como exemplo desta utilização,

pode-se observar em Cadastro.jsp, no quadro anteriormente apresentado, o uso de livro.autor e livro.autor.selection que são associados

aos respectivos valores, conforme quadro abaixo:

...

  1. Livro Labels #
livro.titulo=Título
livro.autor=Autor
livro.genero=Gênero
livro.idioma=Idioma
livro.formatoRelatorio=Apresentar em
livro.relatorio=Relatório
livro.autor.selection=Seleção de Autor
...

ApplicationResources.properties

 

Campo auto-completar

Um modelo de campo auto-completar foi implementado na tela de cadastro para o preenchimento do campo 'gênero'. A implementação do

campo auto-completar está representada pelo trecho de código (de Cadastro.jsp) apresentado no quadro da seqüência e utiliza uma lista

de gêneros criada por uma operação de CadastroAction.java. Foi utilizada uma tag do Ajax (ajax:autocomplete) em conjunto com uma ação

representada por actionType=autocomplete que corresponde à operação implementada por CadastroAction.java. Para um melhor entendimento

das tags do Ajax utilizadas no Projeto de Interface Padrão é conveniente consultar: http://ajaxtags.sourceforge.net/usage.html.

<tr>
<td class="label">
<label for="bookGenre"><fmt:message key="livro.genero"/>:</label>
</td>
<td>
<html:text property="genero" styleId="genero" style="width: 150px;"/>(autocompletar)
<span id="indicator" style="display:none;"><html:img align="top"
page="/img/indicator.gif"/></span>
<ajax:autocomplete
source="genero"
target="genero"
baseUrl="${pageContext.request.contextPath}/livro/cadastro.do"
parameters="actionType=autocomplete,genero={genero}"
className="autocomplete"
minimumCharacters="1"
indicator="indicator">
</ajax:autocomplete>
</td>
</tr>

Código Tela de Cadastro de Livros

public ActionForward autocomplete(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {

configurar o header para não fazer cache
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
recuperar o valor a ser pesquisado da requição
String genero = request.getParameter("genero");

recuperar a lista com os valores disponíveis
List generosList = this.getGeneros();
Para testar como não existem entidades serão criados itens com nome/valor
List itensList = new ArrayList();
for (Object strGenero: generosList) {
if(genero != null){

filtrar os gêneros caso o filtro seja recebido
if(((String)strGenero).toLowerCase().indexOf(genero.toLowerCase()) >= 0){
itensList.add(new Item((String)strGenero, (String)strGenero));
}
}
else {
itensList.add(new Item((String)strGenero, (String)strGenero));
}
}
utilizar o helper do AjaxTags para criar o XML dos dados
String ajaxXML = new AjaxXmlBuilder().addItems(itensList, "name", "value").toString();

escrever o conteúdo XML do Ajax para a saída
ServletOutputStream out = response.getOutputStream();
out.print(ajaxXML);
out.close();
não redirecionar para uma visão
return null;
}

Ação de Cadastro do Livro

 

Combo-box

Foi implementado um modelo de utilização de combo-box na tela de cadastro, especificado pelo trecho de código destacado em amarelo

no quadro abaixo. A maioria dos componentes de interação das interfaces com o usuário foram estabelecidos a partir de tags JSTL e do

próprio Struts, como por exemplo: html:select e html:option, uma lista detalhada das tags html pode ser obtida na documentação do Struts.

<tr>
<td class="label">
<label for="bookGenre"><fmt:message key="livro.genero"/>:</label>
</td>
<td>
<html:select property="genero" styleId="bookGenre" style="width: 150px;" >
<c:forEach items="${requestScope'generos'}" var="genero">
<html:option value="${genero}">${genero}</html:option>
</c:forEach>
</html:select>
</td>
</tr>

Código Tela de Cadastro de Livros

public ActionForward carregar(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)

throws Exception {
gêneros disponíveis para seleção
request.setAttribute("generos", this.getGeneros());
idiomas disponíveis para seleção
request.setAttribute("idiomas", this.getIdiomas());

retornar para a edição do cadastro
return mapping.findForward(FWD_EDIT);
}

private List getIdiomas(){
return Arrays.asList( new String
{"Portugues","Ingles","Espanhol","Outra"});
}

private List getGeneros(){
return Arrays.asList( new String
{"Auto Ajuda","Bibliografia","Comedia","Drama","Policial","Tecnico"});
}

Ação de Cadastro do Livro
 

Radio Button

Um outro componente de interação disponibilizado na tela de cadastro a partir da configuração de uma tag html é o Rádio Button. No trecho de

código destacado em amarelo no quadro abaixo, pode-se verificar a especificação do rádio button segundo definição da variável de contexto

'idiomas' que é configurada conforme operação getIdiomas() de CadastroAction.java.

<tr>
<td class="label"><label><em>*</em><fmt:message key="livro.idioma"/>:</label></td>
<td>
<c:forEach items="${requestScope'idiomas'}" var="idioma" varStatus="status">
<html:radio styleId="idioma${status.index}" property="idioma"
value="${idioma}">${idioma}</html:radio><br/>
</c:forEach>
</td>
</tr>

public ActionForward carregar(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
gêneros disponíveis para seleção
request.setAttribute("generos", this.getGeneros());

idiomas disponíveis para seleção
request.setAttribute("idiomas", this.getIdiomas());
retornar para a edição do cadastro
return mapping.findForward(FWD_EDIT);
}

private List getIdiomas(){
return Arrays.asList( new String{
"Portugues","Ingles","Espanhol","Outra"});
}

 

Campo Data

Adição do componente de calendário Tigra Calendar utilizado na tela de filtro do relatório para dois campos do tipo data para indicar o período

que deve ser invocado pela função openCalendar($('livroFiltroRelatorioForm').DATA_INICIO); segundo o javadoc desta função no arquivo

arquivo javascript.


Também foi adicionado o componente de máscara de campos que adiciona um listener ao campo através da adição da classe de estilo

class="text input_mask mask_date_br" para que o componente realize a formatação do dado no campo. Novas máscaras podem ser

adicionadas de acordo com a necessidade dos projetos, no exemplo acima foi utilizada a máscara (dd/MM/yyyy) de data por ser um campo

deste tipo.
 

Continuar Cadastrando

Na tela de cadastro o checkbox 'Continuar Cadastrando' é inicialmente habilitado conforme valor da propriedade continuarCadastrando em

struts-config.xml e <html:hidden property="continuarCadastrando" value="false"/> possibilita que a referida propriedade mude seu valor para

'false' quando o checkbox for desabilitado.

...
<!-- ###### Livro Forms ##### -->
<form-bean name="livroCadastroForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="id" type="java.lang.String"/>
<form-property name="titulo" type="java.lang.String"/>
<form-property name="idAutor" type="java.lang.String"/>
<form-property name="nomeAutor" type="java.lang.String"/>
<form-property name="genero" type="java.lang.String"/>
<form-property name="idioma" type="java.lang.String"/>
<!-- Campos de seleção para continuar cadastrando -->
<form-property name="continuarCadastrando" type="java.lang.Boolean" initial="true"/>
<!-- Campo para definir estado/validação qdo utilizando wizard -->
<form-property name="page" type="java.lang.Integer" initial="1"/>
</form-bean>
...
...
<action path="/livro/cadastroSave"
type="gov.tjpr.inteface.client.livro.action.CadastroSaveAction"
scope="request"
name="livroCadastroForm"
input="/livro/cadastro.do?actionType=carregar"
validate="true">
<!-- flag for indicating that resource security isn't required -->
<set-property property="checkPermission" value="false"/>
<forward name="new" path="/livro/cadastro.do?actionType=criar" redirect="true"/>
<forward name="detail" path="/livro/detalhe.do" redirect="true"/>
</action>
...

struts-config.xml

<html:form styleId="livroCadastroForm" action="/livro/cadastroSave" focus="titulo" onsubmit="disableScreen();"> 
... <td colspan="2" align="right">
<c:if test="${empty requestScope'livroCadastroForm'.map.id}">
<html:checkbox property="continuarCadastrando" styleId="keepRegistering" />
<label for="keepRegistering" class="checkboxLabel">
<fmt:message key="msg.keep.registering"/>
</label><br/>
</c:if>
</td>
...
<td class="buttons" width="220">
<%-- campo escondido para voltar o valor para falso do checkbox --%>
<html:hidden property="continuarCadastrando" value="false"/>
<html:submit property="submitButton" styleClass="button" styleId="saveButton">
<fmt:message key="button.save"/>
</html:submit>
<html:button property="cancelButton" styleClass="button" styleId="cancelButton"
onclick="disableScreen(); history.back(-1);">
<fmt:message key="button.cancel"/>
</html:button>
</td>

...

Código Tela de Cadastro de Livros

Um evento do botão salvar (saveButton) está associado à ação /livro/cadastroSave relacionada ao arquivo CadastroSaveAction.jsp. Quando

'execute' for acionado pelo evento do botão salvar será retornado um ActionForward equivalente ao valor de continuarCadastrando.

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
recuperar o form associado
DynaActionForm dynaForm = (DynaActionForm)form;

criar coleção das mensagens
ActionMessages messages = new ActionMessages();
adicionar as mensagens à lista de mensagens
messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(MSG_DATA_REGISTERED));

salvar as mensagens para exibir
saveMessages(request.getSession(), messages);
verificar se deve continuar cadastrando ou ir para o detalhe
return (Boolean)dynaForm.get("continuarCadastrando")
? mapping.findForward(FWD_NEW) : mapping.findForward(FWD_DETAIL);
}

Ação de Cadastro do Livro

Tela de Pesquisa de Chave Estrangeira

A tela de pesquisa de chave estrangeira é um recurso implementado, principalmente, para ser utilizado a partir de uma tela de cadastro.

Acima já foi feita uma abordagem preliminar da utilização da Tela de Pesquisa de Chave Estrangeira.

Na seqüência serão descritos os principais mecanismos de implementação de uma Tela de Pesquisa de Chave Estrangeira.
 

Simples
Múltiplo
 
Múltiplo em Árvore
<tr>
<td class="label">
<label for="bookAuthor"><em>*</em><fmt:message key="livro.autor"/>:</label>
</td>
<fmt:message var="popupTitle" key="livro.autor.selection"/>
<crypto:encryptUrl value="/autor/pesquisaSelecaoFilter.do" var="popupURL" />
<td>
<html:hidden property="idAutor"/>
<html:text property="nomeAutor" readonly="true" styleId="bookAuthor" size="40"/>
<a href="javascript:openDialog('${popupURL}','${popupTitle}',400,300);"
class="searchButton" title="Pesquisar Autor"><span>Pesquisar Autor</span>
</a>
</td>
</tr>

Código Tela de Cadastro de Livros

<action path="/autor/pesquisaSelecaoFilter"
type="org.apache.struts.actions.ForwardAction"
scope="request"
parameter="autor.pesquisa.selecao"
name="autorPesquisaForm">
<!-- flag for indicating that resource security isn't required -->
<set-property property="checkPermission" value="false"/>
</action>

Ação de Cadastro do Livro

<definition name="autor.pesquisa.selecao" extends="layout.popup">
<put name="content" value="/jsp/autor/pesquisaSelecao.jsp"/>
</definition>

tiles-definitions.xml

onde:
  • url: endereço completamente qualificado a partir do qual deve ser obtido o conteúdo a ser mostrado no popup. Pode ser tanto uma action,
  • um jsp, html, etc.
  • Titulo*8: o texto que vai aparecer na barra de título do popup.
  • L: largura, em pixels do popup.
  • H: altura, em pixels do popup.

Retornando os dados da Tela de Chave Estrangeira

É possível selecionar um ou muitos dados para serem retornados à tela que invocou a tela de chave-estrangeira.
Este retorno já se encontra encapsulado em funções javascripts implementadas no arquivo \interfaceWeb\web\js\tjpr.js. Para maiores

informações consultar a documentação constante no próprio arquivo javascript.
Basicamente o que se deve fazer é escolher a maneira mais adequada de se fazer o retorno e então usar a função javascript apropriada.

Via Javascript

Neste caso os valores a serem repassados já encontram-se carregados no cliente, e o que ocorre é só uma passagem de valores entre os

formulários das janelas.

Um exemplo desse repasse pode ser encontrado no jsp \interfaceWeb\web\jsp\autor\pesquisa.jsp

A função que dispara o envio é:
function selectAutor(){
formulário de seleção (atual)
var form = 'autorPesquisaForm';

formulários pai que poderão ser selecionados (aonde a pop-up será reutilizada)
var parentForms = 'livroPesquisaForm', 'livroPesquisaMultiplaSelecaoForm', 'livroPesquisaDetalhadaForm', 'livroCadastroForm', 'notafiscalItemForm','livroPesquisaArvoreForm','livroFiltroRelatorioForm';
campos do formulário que serão selecionados (input)
var formFields = 'selection', 'label', 'label', 'label', 'valor', 'valor', 'livro', 'idLivro';

campos dos formulários pai que serão selecionados (output)
var parentFormFields = 'idAutor', 'nomeAutor', 'autorLivro', 'autorLivroDiv', 'valorLivro', 'valorLivroDiv', 'tituloLivro', 'idLivro';
selecionar os campos do autor para os campos da página pai e fechar a janela atual
setParentSelection(form, parentForms, formFields, parentFormFields);
}

Onde:

  • parentForms contém os nomes dos formulários que podem chamar tal tela, pois é possível que a mesma tela estrangeira seja chamada
  • por várias telas diferentes.
  • formFields contém os nomes dos campos do formulário atual que serão repassados aos campos dos formulários “chamadores”.

Note que estes podem ser repetidos, pois cada posição deste array indica que valor será preenchido no campo de mesma posição indicado

no array formParentFields.

  • parentFormFields contém os nomes dos campos do formulário que chamou a tela. Note que este array contém TODOS os campos

     possíveis de serem preenchidos de todos os formulários “chamadores”. Por exemplo: em Form1 pode haver o campo1 e campo2,

     mas no FormA temos o campoA e o campoB. Neste array teremos {campo1, campo2, campoA, campoB}


Por fim ocorre a chamada da função padrão setParentSelection que executará o resto do trabalho.

Via Submit

Neste caso os dados são repassados através da chamada de uma ação no servidor através de um Submit do formulário. Neste caso é

preciso que o servidor esteja preparado para receber os dados da Tela de Chave Estrangeira e repassá-los novamente ao formulário que

chamou a tela.

Um exemplo desse repasse pode ser encontrado no jsp \interfaceWeb\web\jsp\contato\pesquisa.jsp

A função que dispara o envio é:
function selectContato(){
formulário de seleção (atual)
var form = 'contatoPesquisaForm';

urls do formulário atual que poderão ser submetidas para selecionar os items do form (input) de acordo com o índice do form pai
var formURLs = No InterWiki reference defined in properties for Wiki called "';
formulários pai que poderão ser selecionados (aonde a pop-up será reutilizada)
var parentForms = 'notafiscalForm';

urls dos forms pai que serão selecionados (output) para atualizar
var parentFormURLs = No InterWiki reference defined in properties for Wiki called "';
submitParentSelection(form, parentForms, formURLs, parentFormURLs);
}

Onde:

  • formURLs contém as URLs para onde esta tela pode ser submetida. Neste caso o servidor é que sabe o que fazer com os dados que

       receber.

  • parentFormURLs contém as URLs das telas “chamadoras” para que aconteça o refresh na volta dos dados.

Por fim ocorre a chamada da função padrão submitParentSelection que executará o resto do trabalho.