Este é o primeiro de uma série de posts que devem vir sobre como o Merlin suporta a customização das telas de cadastro.
Muitos desses posts são idéias que podem se concretizar ou não. Enfim, o que vale é o espaço para discussões, objetivando chegar à melhor solução.
Uma tela simples
Supomos que temos um bean muito simples, como:
class Pessoa {
String nome;
String historico;
}
Para esse bean, ao fazer a geração (ops, renderização!) da Tela de Cadastro com o Merlin, chegamos a isso:
Como não existe informação de contexto alguma, esta tela é o melhor que podemos fazer nesse momento.
Evoluindo as telas simples
Porém, o usuário espera que o campo historico seja um campo textual para escrever bastante coisa, e assim, usando uma anotação do próprio Hibernate, podemos fazer a evolução:
class {
String nome;
@Length(max=5000)
String historico;
}
Com isso, o resultado da renderização da tela de cadastro é algo como (as setas indicam o redimensionamento):
Mais evoluções
Mas, mesmo assim, o usuário não está satisfeito. Ele quer um resultado como:
Nessa tela, o campo historico continua sendo renderizado como uma caixa de texto simples e possui um botão extra que, ao ser clicado, abre uma outra tela para então, aí sim, termos todo o texto de histórico do cliente!
Como conseguir isso usando o Merlin?
class Pessoa {
String nome;
@Length(max=5000)
@RenderAs(JtextField.class)
String historico;
@RenderAs(value=JButton.class, init=”text='...'”)
@Agent(event=”onClick”, event=”showPopup”)
@Merge(“historico”)
String botao;
}
E pronto. E pronto? Mas como assim?
Explicação
A primeira anotação @RenderAs, indica que o campo historico deve ser mostrado como uma caixa de texto, que será redimensionável horizontalmente (devido o tamanho de 5000), mas que terá apenas uma linha (pois é uma caixa de texto, e não um “textArea”).
A segunda anotação @RenderAs faz com que o campo botao seja renderizado na tela de cadastro como um botão com a propriedade text inicializada com uma String de reticências.
A anotação @Agent adiciona um tratador de eventos ao controle, indicando que ao ser clicado, o método showPopup seja executado (vide mais informações ao final do post).
A anotação @Merge é o kernel da coisa. Ela implica que o botão renderizado seja combinado ao texto do histórico. Em outras palavras, é como se o controle de histórico fosse encapsulado em um painel e nesse painel também fosse adicionado o botão. Essa anotação suporta mais coisas, como a especificação de um layout diferenciado para esse painel, eventos, etc. Mas não precisamos disso aqui. Na prática, essa anotação é muito parecida com @Group, a qual devemos falar em outras oportunidades...
Conclusões
Essa tela de cadastro é bem simples, mas a idéia é essa mesmo.
Como estamos iniciando o nosso framework, nada melhor do que pensar em situações que podem ocorrer e, conforme conseguirmos resolvê-las, irmos incrementando-as em complexidade.
A cada passo, devemos olhar o passado e tentar manter a compatibilidade ou, então, repensar as coisas. É assim mesmo.
Estamos fazendo várias simulações “em casa” e, tão logo tenhamos tempo para postar, bem, é isso que faremos :)
Mais explicações
O leitor atento vai questionar: Mas o Swing (que é o pacote UI inferido no exemplo devido o uso do Jbutton e do JTextField) não possui um evento onClick. Como se explica isso? Como funciona?
Rapidamente, a resposta é: O Merlin suporta aliases de nomes (e não só para eventos, mas para tudo – classes, métodos, etc.). Logo, tanto faz se escrever onClic, doClick, actionPerformed, etc. E o melhor de tudo, é que esses aliases são criados conforme o gosto do usuário e de forma facilitada, propagando-se (ou não) por todo o contexto da aplicação e mesmo de várias aplicações, caso seja de interesse. E claro, são intercambiáveis entre pacotes gráficos diferentes. Uma loucura, como diria um amigo meu...
A segunda pergunta é: E o método showPopup? Este método é obtido por inferência de proximidade. Primeiro, o Merlin tenta localizá-lo no próprio bean vinculado à tela. Não encontrando, procura métodos de aliases no contexto do formulário (por exemplo, se usado Web Beans ou Seam, seria um método de EJB ou análigo que tivesse a anotação @WebMethod) ou códigos de scripting (groovy, beanshel, etc) associados ao formulário. Se não encontrado, ele procura na hierarquia de classes do bean. Se encontrado, ele instancia esse bean e executa o método. Não encontrando, ele procura pelo escopo (primeiro) da aplicação – partindo dos pacotes mais próximos ao bean, e (depois) por todas as aplicações atingíveis pelo classloader da aplicação corrente. Nesse caso de busca por escopo, ele procura primeiro por classes com métodos públicos anotados com @Action (em classes ou métodos) e depois por métodos públicos somente. Toda essa busca é built-in da ferramenta, podendo ser customizada, sobreescrita ou desabilitada.
E ao leitor mais “bicudo” (ahah, lembrei o apelido que eu tinha na época que eu fazia curso de computação antigamente...) vai questionar? E como os parâmetros são passados para o método showPopup? No caso onde o método está diponível no próprio bean, não tem mistério: é acesso direto. Para os outros casos, é possível implementar uma interface InvocationContext, tal como no mundo dos EJBs ou usar a anotação @In, como no mundo do Seam/Web Beans. Outra forma é usar a API da ferramenta.
Nenhum comentário:
Postar um comentário