Assistente de Campo

Muitas vezes, espera-se que um usuário forneça informações textuais em um campo simples, como um campo de texto ou uma caixa de combinação. Embora o código do aplicativo que preenche esses campos em geral sejam muito mais simples do que o código que preenche um widget complexo, como uma tabela ou uma árvore, esses campos "simples" normalmente aumentam a responsabilidade do usuário. O usuário deve identificar quais campos exigem conteúdo, se um campo contém conteúdo válido e quais opções são esperadas. O suporte de assistente de campo do JFace fornece classes que ajudam a guiar o usuário pelas tarefas de entrada.

O pacote org.eclipse.jface.fieldassist fornece assistência de duas maneiras. O suporte para campos decorados permite incluir decorações de imagem que dão sugestão ao usuário sobre o status de um determinado campo. O suporte a Proposta de Conteúdo permite fornecer uma pop-up de assistente de conteúdo que fornece opções de conteúdo para o usuário.

Campos Decorados

Campos decorados permitem colocar decorações de imagem adjacentes aos campos definidos em uma janela ou diálogo. Decorações podem ser colocadas adjacentes a um dos quatro cantos de um campo. Muito semelhantes aos visualizadores, campos decorados destinam-se a incluir funcionalidade em um controle do SWT, embora ainda fornecendo acesso ao controle subjacente. A API para DecoratedField permite incluir, ocultar e mostrar decorações adjacentes a um campo. O acesso ao controle subjacente é fornecido para que você possa utilizar a API do SWT existente para afetar o controle subjacente, como definir seu conteúdo, cor ou fonte.

Criando um Campo Decorado

Externamente, um campo decorado se comporta como um único controle. Internamente, campos decorados utilizam um controle composto para gerenciar o layout do campo e suas decorações. Na maioria dos casos, isso não deverá ter importância para o aplicativo cliente. Entretanto, significa que o campo decorado deve executar a criação real do controle. Por exemplo, considere esse snippet, no qual um aplicativo cria um controle de texto em um de seus diálogos:

...
// Criar um campo de texto
Text text = new Text(parent, SWT.BORDER);
text.setText("some text"); 
...

Para decorar esse campo, o campo seria criado desta maneira:

...
// Criar um campo decorado para um controle de texto
DecoratedField field = new DecoratedField(parent, SWT.BORDER, new TextControlCreator());
Text text = (Text)field.getControl();
text.setText("some text");
...

O mesmo pai e bits de estilo que seriam utilizados para criar o controle básico também são utilizados para criar um campo decorado. A diferença principal no código é que é fornecida uma instância de IControlCreator que cria o tipo específico de controle desejado no campo. Para campos de texto, você pode utilizar a classe TextControlCreator para criar o controle. No entanto, você tem a flexibilidade para implementar IControlCreator para criar qualquer outro tipo de controle no campo, como uma caixa de combinação ou spinner.

Utilizando Decorações

Uma vez criado um campo decorado, as decorações podem ser incluídas nele, em um de quatro locais. As constantes de local do SWT são utilizadas para especificar onde a decoração deve ser colocada. Para incluir uma decoração, é necessário especificar um FieldDecoration, que define a imagem da decoração e o texto descritivo (opcional) que pode ser mostrado quando o usuário passa o mouse sobre a decoração.

...
// Criar uma decoração de campo e incluí-la no campo
Image image = JFaceResources.getImage("myplugin.specialimage");
FieldDecoration mySpecialDecoration = new FieldDecoration(image, "Este campo é especial");
field.addFieldDecoration(mySpecialDecoration, SWT.TOP | SWT.LEFT, false);
...

O parâmetro booleano é utilizado para especificar se a decoração deverá ser mostrada somente quando o controle tiver o foco, ou todas as vezes. Nesse caso, a decoração será mostrada todo o tempo. Entretanto, pode haver outras vezes em que a decoração deverá ficar oculta ou ser mostrada. O seguinte snippet oculta uma decoração que já foi criada.

...
// Ocorreu algo que me faz querer ocultar a decoração
field.hideDecoration(mySpecialDecoration);
...

Se a imagem ou a descrição de uma decoração for atualizada, o campo deverá ser notificado, para que a decoração possa ser redesenhada.

...
// Algo tornou o campo extra-especial
mySpecialDecoration.setDescription("Este campo é extra-especial");
field.updateDecoration(mySpecialDecoration);
...

Traçando Campos Decorados e Não Decorados

Ao traçar um campo decorado em um diálogo ou uma janela, trace o controle de layout do campo em vez do controle simples subjacente. Considere novamente o código para criação de um controle de texto. Ao traçar um controle de texto, o aplicativo define dados de layout no controle.

...
// Criar um campo de texto
Text text = new Text(parent, SWT.BORDER);
text.setText("some text");
// Definir os dados de layout
GridData data = new GridData(IDialogConstants.ENTRY_FIELD_WIDTH, SWT.DEFAULT);
text.setLayoutData(data); 
...

Ao traçar um campo decorado, o aplicativo deverá deixar os dados de layout no controle de layout do campo. Dependendo do layout desejado, o tamanho do campo talvez tenha de ser ajustado para o tamanho da decoração.

...
// Criar um campo decorado para um controle de texto
DecoratedField field = new DecoratedField(main, SWT.BORDER, new TextControlCreator());
Text text = (Text)field.getControl();
text.setText("some text");
// Definir os dados de layout
GridData data = new GridData(IDialogConstants.ENTRY_FIELD_WIDTH + 
   FieldDecorationRegistry.getDefault().getMaximumDecorationWidth(), SWT.DEFAULT);
field.getLayoutControl().setLayoutData(data); 
...

O suporte de assistente de campo não exige ou presume que você esteja utilizando somente campos decorados em um determinado diálogo ou janela. Entretanto, o layout da janela pode se tornar um pouco mais complicado quando campos decorados são misturados com controles simples. Para alinhar campos decorados e não decorados, leve em conta o recuo criado pela largura da decoração. A largura de uma decoração é simplesmente a largura de sua imagem. Entretanto, as coisas poderão ficar mais complicadas se você estiver utilizando decorações com larguras diferentes. Nesse caso, será possível simplificar isso registrando todas as decorações no FieldDecorationRegistry.

Registro de Decoração de Campo

O registro de decoração de campo permite registrar e acessar as decorações de campo utilizando um id de cadeia. Isso oferece uma maneira prática de referência às decorações utilizadas em todo o aplicativo. Você poderá optar por definir a API que expõe os ids de decoração se desejar torná-los disponíveis a outros plug-ins. Observe que o registro de uma decoração não gerencia o ciclo de vida das imagens nessas decorações. O aplicativo pode decidir como gerenciar essas imagens. Por exemplo, o registro de imagem JFace pode ser utilizado para registrar e gerenciar o ciclo de vida da imagem. Alternativamente, o aplicativo pode desejar criar a imagem on demand e descartá-la quando ela não for mais necessária. O javadoc para os métodos de registro em FieldDecorationRegistry explica os diferentes modos nos quais as imagens podem ser especificadas ao registrar uma decoração.

O registro das decorações no registro de decoração de campo também pode simplificar o processo de layout ao maximizar campos decorados (e não decorados). Por padrão, um campo decorado consultará o registro de decoração de campo para determinar a largura máxima de uma decoração e assegurar-se de que todas as decorações utilizem essa largura. Isso significa que todos os campos decorados serão alinhados de forma correta, independentemente da largura de uma determinada decoração. Para alinhar campos não decorados, você pode utilizar o protocolo FieldDecorationRegistry para acessar a largura da decoração maior e criar o recuo necessário.

...
// Criar um campo de texto
Text text = new Text(parent, SWT.BORDER);
text.setText("some text");
// Definir os dados de layout
GridData data = new GridData();
data.horizontalAlignment = SWT.FILL;
data.horizontalIndent = FieldDecorationRegistry.getDefault().getMaximumDecorationWidth();
text.setLayoutData(data); 
...

Embora o suporte de assistente de campo não indique como as decorações devem ser utilizadas, o registro também define decorações padrão que podem ser utilizadas pelos aplicativos para mostrar determinados estados de um campo. Por exemplo, o seguinte snippet utiliza uma decoração padrão para campos obrigatórios:

...
// Criar um campo decorado com uma decoração de campo obrigatório.
DecoratedField field = new DecoratedField(main, SWT.BORDER, new TextControlCreator());
FieldDecoration requiredFieldIndicator = FieldDecorationRegistry.getDefault().
   getFieldDecoration(FieldDecorationRegistry.DEC_REQUIRED);
field.addDecoratedField(requiredFieldIndicator, SWT.BOTTOM | SWT.LEFT, false);
...

Propostas de Conteúdo

Além de campos de anotação com decorações, os aplicativos podem fornecer um assistente de proposta de conteúdo que ativa uma pop-up de proposta para um campo. Você pode instalar um ContentProposalAdapter em um controle arbitrário para fornecer esse comportamento. O seguinte snippet instala um adaptador de proposta de conteúdo em um controle de texto. Observe que esse controle de texto pode ser um controle criado diretamente pelo aplicativo ou um obtido de um campo decorado.

...
autoActivationCharacters = new char[] { '#', '(' };
keyStroke = KeyStroke.getInstance("Ctrl+Space");
// suponha que myTextControl já tenha sido criado de alguma maneira
ContentProposalAdapter adapter = new ContentProposalAdapter(
	myTextControl, new TextContentAdapter(),
	new SimpleContentProposalProvider(new String [] {"ProposalOne", "ProposalTwo", "ProposalThree"}),
	keyStroke, autoActivationCharacters);

Para obter e definir o conteúdo do controle quando o usuário escolhe uma proposta na pop-up, o adaptador deve receber uma instância de IControlContentAdapter, que pode recuperar e definir o conteúdo de um determinado tipo de controle. Para campos de texto, você pode utilizar a classe TextContentAdapter. Entretanto, você tem a flexibilidade para implementar IControlContentAdapter a fim de utilizar o adaptador de proposta de conteúdo com qualquer outro tipo de controle.

Ao criar um adaptador de proposta de conteúdo, você deve especificar também uma instância de IContentProposalProvider, a partir da qual as próprias propostas serão recuperadas. Esse provedor é responsável por retornar uma matriz de propostas de conteúdo. As próprias propostas são especificadas como instâncias de IContentProposal, das quais o rótulo e o conteúdo da proposta podem ser obtidos, além de outras informações, como uma descrição detalhada da proposta.

No exemplo anterior, é utilizado o SimpleContentProposalProvider. Esse provedor é definido especificando uma matriz simples de Cadeias como as propostas de conteúdo. O provedor simples implementa o protocolo necessário para mapear cada cadeia no IContentProposal esperado. A flexibilidade de IContentProposalProvider permite implementar um provedor de proposta com recursos avançados, como filtrar as propostas com base no conteúdo de controle, fornecer rótulos explicativos na pop-up em vez do conteúdo real que será inserido e especificar a posição esperada do cursor após uma proposta ser inserida. Consulte o Exemplo de Assistente de Campo e procure os implementadores de IContentProposalProvider para uso avançado.

Configurando um Adaptador de Proposta de Conteúdo

Vimos que a definição básica de um adaptador de proposta de conteúdo inclui o controle para que as propostas sejam fornecidas, o adaptador de conteúdo utilizado para alterar o conteúdo do controle e o provedor de proposta que define a lista de propostas na pop-up. Além desses itens básicos, há várias maneiras de configurar o adaptador de proposta de conteúdo:

O Exemplo de Assistente de Campo permite configurar essas várias opções nas preferências de exemplo e tentar as diferentes combinações. Por exemplo, o adaptador pode ser configurado para ser chamado explicitamente com um pressionamento de tecla e insira o conteúdo de proposta no controle, fazendo com que ele se comporte de forma muito semelhante ao assistente de conteúdo do editor de texto. Ou ele pode ser configurado sem pressionamento de tecla específico, caracteres de ativação automática e substituição de conteúdo, para que se comporte de forma mais parecida com o estilo de preenchimento de entrada direta utilizado na URL do navegador da Web ou em campos de procura. Consulte o javadoc para obter informações mais específicas sobre cada um desses métodos e como eles agem entre si.

Assistente de Campo do Ambiente de Trabalho

O suporte de assistente de campo no nível JFace oferece ao seu aplicativo muita flexibilidade na determinação de como decorar campos e mostrar propostas de conteúdo de campo. Isso é desejável para aplicativos JFace ou aplicativos cliente rich independentes. Entretanto, se o aplicativo tiver sido planejado para integração com outros plug-ins, como o Eclipse SDK ou plug-ins de terceiros, provavelmente você irá querer utilizar o suporte de assistente de campo de maneira consistente com outros plug-ins. O ambiente de trabalho define as classes do utilitário que usam o assistente de campo para tipos específicos de interações.

Por exemplo, a classe ContentAssistField cria um campo que inclui uma decoração de lâmpada para avisar ao usuário que o assistente de conteúdo está disponível. Ela também configura um adaptador de proposta de conteúdo para inserção de estilo do assistente de conteúdo. Por último, ela fornece um manipulador para o comando do assistente de conteúdo do nível do ambiente de trabalho para que a pop-up de proposta de conteúdo seja aberta quando o usuário chamar o pressionamento de tecla ou acionar a seqüência que foi especificada nas ligações de teclas do ambiente de trabalho. Consulte o pacote org.eclipse.ui.fieldassist para obter mais detalhes sobre essas classes de utilitário.

Espera-se que esse pacote se desenvolva à medida que o ambiente de trabalho expande seu uso do assistente de campo e padronize o uso de decorações para determinados estados de campo.