Apresentaremos a partir de agora um exemplo de uso do pattern Presentation
Model com a API JGoodies Binding. O
código completo está disponível para download no site da Java Magazine (para rodar o exemplo, basta executar a classe Programa).
Além da API Binding você vai precisar das APIs Forms e Looks do JGoodies. Para obtê-las, no site do projeto ( jgoodies.com) vá
até a seçãoDownload e clique emLibraries.
Lá você terá acesso aos arquivos zipados de todas as APIs, contendo exemplos, do- cumentação, código-fonte e os JARs que devem ser incluídos no classpath da sua aplicação.
Apresentando a aplicação
O exemplo que vamos construir é um cadastro de usuários conforme apresen- tado na Figura 3. É mostrada uma lista contendo todos os usuários cadastrados; as informações do usuário selecionado são exibidas à direita. Cada usuário possui quatro atributos: o nome, o cargo, e dois indicadores definindo se é administrador e se tem acesso ao controle de permissões da aplicação. O acesso ao controle de permis- sões só é possível para administradores.
Um título no lado direito apresenta qual usuário estamos editando. Se nenhum estiver selecionado, é apresentado o texto “Nenhum usuário selecionado” e todos os componentes de edição ficam desabi- litados.
A classe Usuario
Começaremos construindo o exem- plo pela classe Usuario, mostrada na Listagem 1. Para essa classe JavaBean, o ponto mais importante a destacar é a emissão de eventos, que é realizada quando os dados do usuário são alterados. Precisamos implementar isso porque as classes da API Binding exigem que os objetos manipulados sejam observáveis3. Assim sendo, o primeiro passo é fazer a classe Usuario herdar da classe Model(pa- cotecom.jgoodies.binding.beans); em seguida alteramos todos os métodos setXxx() para que chamem firePropertyChange() e, dessa forma, avisem que a propriedade em questão mudou seu valor.
A classe Presentation Model
A segunda classe que vamos desenvolver chama-se CadastroUsuarioPresentationModel (Listagem 2). Conforme vimos naFigura 1, essa classe deve possuir
uma referência para a clas-
se Service Layer, que é o
único meio de comunica- ção da GUI com o resto do software. Assim, o cons- trutor da classe recebe e guarda um objeto do tipo CadastroUsuarioServiceLayer, que é explicado mais adiante.
Ainda no construtor, repare a cha- mada de dois métodos: iniciaModelos() e iniciaLogicaApresentacao(). É nesses métodos que o estado e a lógica da GUI começam a surgir. Para entender o código, acompanhe aFigura 4 e veja como a API Binding está sendo usada. A Tabela 1 apresenta um resumo dos objetos citados a seguir.
O métodoiniciaModelos() começa criando o objetousuarioSelectionInList, a partir de um ListModel (usuarioListModel) e um ValueModel (usuarioSelecionadoHolder):
usuarioListModel = new ArrayListModel();
usuarioSelecionadoHolder = new ValueHolder(null, true); usuarioSelectionInList = new SelectionInList((ListModel)
usuarioListModel, usuarioSelecionadoHolder);
Embora ainda não tenhamos explicado a
3Basicamente, um objeto éobservável quando mudan-
ças nele emitem eventos. O objeto que escuta esses even- tos chama-seobservador . Esses são conceitos trazidos pelo patternObserver do livro “Design Patterns” [Gamma et al.].
Figura 3. Tela de cadastro de usuários.
Listagem 1.Classe de modelo Usuario.
import com.jgoodies.binding.beans.Model; public class Usuario extends Model {
public static final String PROPERTY_NOME = “nome”; public static final String PROPERTY_CARG O = “cargo”;
public static final String PROPERTY_ADMI NISTRADOR = “administrado r”;
public static final String PROPERTY_CONTROLE_PERMISSAO = “controlePermissao”; private String nome;
private String cargo;
private boolean isAdministr ador; private boolean isControleP ermissao; public String getNome() {
return nome; }
public void setNome(Str ing nome) { String valorAntigo = this.nome; this.nome = nome;
// Todos os metodos set lançam eventos...
this.fireProp ertyChange(P ROPERTY_NOME, valorAntigo , this.nome); }
/*...Os outros metodos get/set são similares */ }
54 Java Magazine•Edição 39 import com.jgoodies.binding.beans.*; import com.jgoodies.binding.list.*; import com.jgoodies.binding.value.*; import javax.swing.*; import java.awt.event.ActionEvent; import java.beans.*; import java.util.*;
public class CadastroUsuarioPresentationModel extends Model { public static final String TITULO_SEM_SELECAO =
“Nenhum usuário selecionado.”;
public static final String TITULO_COM_SELECAO = “Detalhes de “; private CadastroUsuarioServiceLayer serviceLayer;
private ArrayListModel usuarioListModel;
private BeanAdapter usuarioSelecionadoBeanAdapter; private SelectionInList usuarioSelectionInList; private SelectionInList cargoSelectionInList; private ValueHolder usuarioSelecionadoHolder; private ValueHolder tituloHolder;
private ValueHolder usuarioDisponivelHolder; private ValueHolder campoPermissaoDisponivelHolder; private Action adicionarAction;
private Action removerAction; private Action salvarAction;
public CadastroUsuarioPresentationModel( CadastroUsuarioServiceLayer serviceLayer) { this.serviceLayer = serviceLayer; iniciaModelos(); iniciaLogicaApresentacao(); }
private void iniciaModelos() {
usuarioListModel = new ArrayListModel();
usuarioSelecionadoHolder = new ValueHolder(null, true); usuarioSelectionInList = new SelectionInList(
(ListModel) usuarioListModel, usuarioSelecionadoHolder); usuarioSelecionadoBeanAdapter = new BeanAdapter(
usuarioSelecionadoHolder, true);
ArrayListModel cargoListModel = new ArrayListModel( Arrays.asList(Cargos.TODOS));
cargoSelectionInList = new SelectionInList( (ListModel) cargoListModel, getCargoHolder()); tituloHolder = new ValueHolder();
usuarioDisponivelHolder = new ValueHolder(); campoPermissaoDisponivelHolder = new ValueHolder(); adicionarAction = new AdicionarAction();
removerAction = new RemoverAction(); salvarAction = new SalvarAction(); }
private void iniciaLogicaApresentacao() { ObservadorSelecaoUsuario observadorSelecao = new ObservadorSelecaoUsuario(); usuarioSelecionadoHolder.addValueChangeListener( observadorSelecao); observadorSelecao.propertyChange(null); ObservadorNomeUsuario observadorNome = new ObservadorNomeUsuario(); this.getNomeHolder().addValueChangeListener(observadorNome); observadorNome.propertyChange(null); ObservadorCampoAdmin observadorAdmin = new ObservadorCampoAdmin(); this.getAdminHolder().addValueChangeListener( observadorAdmin); observadorAdmin.propertyChange(null);
PropertyConnector connector = new PropertyConnector( usuarioDisponivelHolder, “value”, removerAction, “ enabled”);
connector.updateProperty2();
List usuarios = serviceLayer.buscaUsuarios(); usuarioListModel.addAll(usuarios);
}
/* Metodos get omitidos */ private void adicionaUsuario() {
Usuario novoUsuario = new Usuario(“Novo Usuário”, null); usuarioListModel.add(novoUsuario);
}
private void removeUsuario() {
int indice = usuarioSelectionInList.getSelectionIndex(); if (indice != -1) {
usuarioListModel.remove(indice); }
}
private void salvaUsuarios() {
List lista = Collections.unmodifiableList(usuarioListModel); serviceLayer.salvaUsuarios(lista);
}
private void habilitaCampos() { boolean enabled =
usuarioSelecionadoHolder.getValue() != null; usuarioDisponivelHolder.setValue(enabled); habilitaCampoControlePermissao();
}
private void habilitaCampoControlePermissao() { Usuario selecionado = (
Usuario) usuarioSelecionadoHolder.getValue(); boolean enabled = selecionado !=
null && selecionado.isAdministrador();
campoPermissaoDisponivelHolder.setValue(enabled); }
/* Inner classes de ações */
private class AdicionarAction extends AbstractAction { public void actionPerformed(ActionEvent e) {
adicionaUsuario(); }
}
private class RemoverAction extends AbstractAction { public void actionPerformed(ActionEvent e) { removeUsuario();
} }
private class SalvarAction extends AbstractAction { public void actionPerformed(ActionEvent e) { salvaUsuarios();
} }
/* Inner classes de observadores */
private class ObservadorNomeUsuario implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) { if (getUsuarioSelecionadoHolder().getValue() == null) { getTituloHolder().setValue(TITULO_SEM_SELECAO); } else { getTituloHolder().setValue(TITULO_COM_SELECAO + getNomeHolder().getValue()); }
// Emite um evento de mudança para que a GUI reflita o novo // nome.
usuarioListModel.fireContentsChanged(
usuarioSelectionInList.getSelectionIndex()); }
}
private class ObservadorSelecaoUsuario implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) { habilitaCampos();
} }
private class ObservadorCampoAdmin implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) { habilitaCampoControlePermissao();
} } }
Listagem 2.Classe CadastroUsuarioPresentationModel, onde fica o estado e a lógica da GUI.
Edição 39• Java Magazine 55