Often, a user is expected to provide textual information in a simple field such as a text field or combo box. Although the application code that populates these fields is generally much simpler than code that populates a complex widget such as a table or tree, these "simple" fields usually place more burden on the user. The user must identify which fields require content, whether a field contains valid content, and what choices are expected. The JFace field assist support provides classes that help guide the user through input tasks.
The org.eclipse.jface.fieldassist package provides assistance in two ways. Support for decorated fields allows you to include image decorations that cue the user about the status of a particular field. Content proposal support allows you to provide a content assist popup that provides content choices for the user.
Decorated fields allow you to place image decorations adjacent to fields defined in a window or dialog. Decorations may be placed adjacent to one of the four corners of a field. Much like viewers, decorated fields are intended to add functionality to an SWT control, while still providing access to the underlying control. The API for DecoratedField allows you to add, hide, and show decorations adjacent to a field. Access to the underlying control is provided so that you can use the existing SWT API to affect the underlying control, such as setting its content, color, or font.
From the outside, a decorated field behaves like a single control. Internally, decorated fields use a composite control to manage the layout of the field and its decorations. For the most part, this shouldn't matter to the client application. However, it means that the decorated field must perform the actual creation of the control. For example, consider this snippet, in which an application creates a text control inside one of its dialogs:
... // Create a text field Text text = new Text(parent, SWT.BORDER); text.setText("some text"); ...
In order to decorate this field, the field would be created in this manner:
... // Create a decorated field for a text control DecoratedField field = new DecoratedField(parent, SWT.BORDER, new TextControlCreator()); Text text = (Text)field.getControl(); text.setText("some text"); ...
The same parent and style bits that would be used to create the basic control are also used to create a decorated field. The primary difference in the code is that an instance of IControlCreator is provided that creates the specific kind of control desired in the field. For text fields, you can use the class TextControlCreator to create the control. However, you have the flexibility to implement IControlCreator to create any other kind of control inside the field, such as a combo box or spinner.
Once a decorated field is created, decorations may be added to it, in one of four locations. SWT location constants are used to specify where the decoration should be placed. To add a decoration, you must specify a FieldDecoration, which defines the image for the decoration, and (optional) descriptive text that can be shown when the user hovers over the decoration.
... // Create a field decoration and add it to the field Image image = JFaceResources.getImage("myplugin.specialimage"); FieldDecoration mySpecialDecoration = new FieldDecoration(image, "This field is special"); field.addFieldDecoration(mySpecialDecoration, SWT.TOP | SWT.LEFT, false); ...
The boolean parameter is used to specify whether the decoration should be shown only when the control has focus, or whether it should be shown at all times. In this case, the decoration will be shown all of the time. However, there may be other times when the decoration should be hidden or shown. The following snippet hides a decoration that has already been created.
... // Something has occurred that makes me want to hide the decoration field.hideDecoration(mySpecialDecoration); ...
If the image or description for a decoration is updated, the field should be notified, so that the decoration can be redrawn.
... // Something has made the field extra special mySpecialDecoration.setDescription("This field is extra-special"); field.updateDecoration(mySpecialDecoration); ...
When laying out a decorated field inside a dialog or window, you should lay out the field's layout control rather than the underlying simple control. Consider again the code for creating a text control. When laying out a text control, the application sets layout data on the control.
... // Create a text field Text text = new Text(parent, SWT.BORDER); text.setText("some text"); // Set the layout data GridData data = new GridData(IDialogConstants.ENTRY_FIELD_WIDTH, SWT.DEFAULT); text.setLayoutData(data); ...
When laying out a decorated field, the application should let the layout data on the field's layout control. Depending on the desired layout, the size of the field may have to be adjusted for the size of the decoration.
... // Create a decorated field for a text control DecoratedField field = new DecoratedField(main, SWT.BORDER, new TextControlCreator()); Text text = (Text)field.getControl(); text.setText("some text"); // Set the layout data GridData data = new GridData(IDialogConstants.ENTRY_FIELD_WIDTH + FieldDecorationRegistry.getDefault().getMaximumDecorationWidth(), SWT.DEFAULT); field.getLayoutControl().setLayoutData(data); ...
The field assist support does not require or assume that you are using only decorated fields inside a particular dialog or window. However, the layout of your window may become a bit more complicated when decorated fields are mixed with simple controls. In order to align decorated and non-decorated fields, you must take into account the indent created by the decoration width. The width of a decoration is simply the width of its image. However, things can get more complicated if you are using decorations with different widths. If this is the case, you can simplify things by registering all of your decorations in the FieldDecorationRegistry.
The field decoration registry allows you to register and access your field decorations using a string id. This provides a convenient way for you to refer to decorations used throughout your application. You may choose to define API that exposes your decoration ids if you wish to make them available to other plug-ins. Note that registering a decoration does not manage the life-cycle of the images inside those decorations. Your application can decide how to manage these images. For example, the JFace image registry may be used to register and manage the image's life-cycle. Alternatively, your application may wish to create the image on demand and dispose of it when it is no longer needed. The javadoc for the registration methods in FieldDecorationRegistry explain the different ways that images can be specified when registering a decoration.
Registering your decorations in the field decoration registry can also simplify the layout process when mixing decorated (and non-decorated) fields. By default, a decorated field will consult the field decoration registry to determine the maximum width of a decoration, and ensure that all decorations use this width. This means that all of your decorated fields will align properly, regardless of the width of any particular decoration. To align non-decorated fields, you can use the FieldDecorationRegistry protocol to access the width of the largest decoration and create the necessary indent.
... // Create a text field Text text = new Text(parent, SWT.BORDER); text.setText("some text"); // Set the layout data GridData data = new GridData(); data.horizontalAlignment = SWT.FILL; data.horizontalIndent = FieldDecorationRegistry.getDefault().getMaximumDecorationWidth(); text.setLayoutData(data); ...
Although the field assist support does not dictate how decorations should be used, the registry also defines standard decorations that can be used by applications to show certain states for a field. For example, the following snippet uses a standard decoration for required fields:
... // Create a decorated field with a required field decoration. 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); ...
In addition to annotating fields with decorations, applications may provide a content proposal assistant that activates a proposal popup for a field. You may install a ContentProposalAdapter on an arbitrary control in order to provide this behavior. The following snippet installs a content proposal adapter on a text control. Note that this text control could be a control created directly by the application or one obtained from a decorated field.
... autoActivationCharacters = new char[] { '#', '(' }; keyStroke = KeyStroke.getInstance("Ctrl+Space"); // assume that myTextControl has already been created in some way ContentProposalAdapter adapter = new ContentProposalAdapter( myTextControl, new TextContentAdapter(), new SimpleContentProposalProvider(new String [] {"ProposalOne", "ProposalTwo", "ProposalThree"}), keyStroke, autoActivationCharacters);
In order to get and set the content of the control when the user chooses a proposal in the popup, the adapter must be supplied with an instance of IControlContentAdapter, which can retrieve and set the contents of a particular kind of control. For text fields, you can use the class TextContentAdapter. However, you have the flexibility to implement IControlContentAdapter to use the content proposal adapter with any other kind of control.
When creating a content proposal adapter, you must also specify an instance of IContentProposalProvider, from which the proposals themselves are retrieved. This provider is responsible for returning an array of content proposals. The proposals themselves are specified as instances of IContentProposal, from which the label and content of the proposal can be obtained, in addition to other information, such as a detailed description of the proposal.
In the example above, the SimpleContentProposalProvider is used. This provider is defined by specifying a simple array of Strings as the content proposals. The simple provider implements the necessary protocol to map each string into the expected IContentProposal. The flexibility of IContentProposalProvider allows you to implement a proposal provider with advanced features, such as filtering the proposals based on the control's content, providing explanatory labels in the popup instead of the actual content that will be inserted, and specifying the expected cursor position after a proposal is inserted. See the Field Assist Example and search for implementors of IContentProposalProvider for advanced usage.
We've seen that the basic definition for a content proposal adapter includes the control for which the proposals are provided, the content adapter used to alter the content of the control, and the proposal provider that defines the list of proposals in the popup. In addition to these basics, there are many ways that the content proposal adapter can be configured:
Field assist support at the JFace level gives your application a lot of flexibility in determining how to decorate fields and show proposals for field content. This is desirable for stand-alone JFace applications or stand-alone rich client applications. However, if your application is intended to integrate with other plug-ins, such as the Eclipse SDK or third-party plug-ins, you will probably want to use the field assist support in a way that is consistent with other plug-ins. The workbench defines utility classes that use field assist for specific kinds of interactions.
For example, the class ContentAssistField creates a field that includes a light bulb decoration to cue the user that content assist is available. It also configures a content proposal adapter for content-assist style insertion. Finally, it provides a handler for the workbench-level content assist command, so that the content proposal popup is opened when the user invokes the keystroke or trigger sequence that has been specified in the workbench key bindings. See the org.eclipse.ui.fieldassist package for more detail about these utility classes.
This package is expected to evolve as the workbench expands its use of field assist and standardizes the use of decorations for certain field states.