Elastic Path UI Framework in Commerce Manager
Overview
The Elastic Path UI Framework is the basis for the user interface of the Commerce Manager.
UI development with the SWT (Standard Widget Toolkit) and JFace libraries used by the Commerce Manager’s underlying RCP (Rich Client Platform) or RAP (Remote Application Platform) framework demands thorough knowledge of the widgets and composites in Eclipse. This has led to the creation of the Elastic Path UI Framework having in mind that it will be an evolving product extended whenever there’s need for that. The balance between building something huge and unmaintainable and having something that will ease the development is really important. For that reason the UI framework should be used for wrapping the most used SWT widgets. For all the particular cases that are not common to the EP RCP the native SWT API should be employed.
The UI framework wraps the SWT widgets and composites. While using it there should always be a way to get the native SWT widget or composite lying beneath the wrapping object. This does not restrict the developer on using only the UI framework once starting a composite with it and makes the development a little bit more flexible.
Development Model
Eclipse has two main component types - composites and controls. The composite acts as a container for controls. Each composite is also a control which allows to nest a composite inside a composite. The SWT UI forms a tree-like structure where the leafs are the various controls visible to the user and branches are the composites holding them and organizing their location and composition.
For building an organized UI a layout has to be utilized. There are various layout managers in Eclipse. The most prominent and powerful are the GridLayout
and TableWrapLayout
. They both are very similar in design. They possess the ability to lay out the components according to a predefined grid. The components are added to the grid from left to right filling the rows from top to bottom. Another task of the layouts is to define how exactly the component should be placed inside the cell. This includes setting the component to stick to the left, right, top or bottom of the cell, stretch and employ the whole available space of the cell or take a number of rows and/or columns in the grid.
For more information on the layouts, please read Understanding Eclipse Layout
Having in mind this simple structure of the composites, controls and layouts the easiest way to abstract that was to create a class wrapping the creation of composites and controls altogether. This was achieved by the IEpLayoutComposite interface. This is the basic interface of the framework. It represents a composite (pane) and has the functionality of adding UI widgets to it.
All methods starting with add
create new component and add it to the composite. The two main methods responsible for nesting composites one into another are
IEpLayoutComposite.addTableWrapLayoutComposite(int numColumns, boolean equalWidthColumns, IEpLayoutData data);
IEpLayoutComposite.addGridLayoutComposite(int numColumns, boolean equalWidthColumns, IEpLayoutData data);
All the add methods have a parameter for the IEpLayoutData
. This interface represents the layout data for the layouts. It abstracts the two different layout data - GridLayoutData
and TableWrapLayoutData
.
The layout data can be created from the IEpLayoutComposite using the createLayoutData(...)
methods. The following picture shows how particular components (marked with blue line) will be placed inside their sells having set the values of the layout data. The six parameters of IEpLayoutData
set on each component are as follows:
horizontalAlignment
- how control will be positioned horizontally within a cellverticalAlignment
- how control will be positioned vertically within a cellgrabExcessHorizontalSpace
- whether cell will be made wide enough to fit the remaining horizontal spacegrabExcessVerticalSpace
- whether cell will be made high enough to fit the remaining vertical spacehorizontalSpan
- the number of column cells that the control will take upverticalSpan
- the number of row cells that the control will take up
If the layout data parameter is set to null when adding new components with the 'add...
' methods, then the default layout data is set for filling the cell both horizontally and vertically but not grabbing vertical/horizontal space.
When creating a new composite the CompositeFactory
class should be used. It creates an instance of the IEpLayoutComposite
with one of the two supported layouts - GridLayout
or TableWrapLayout
. This is not visible to the developer as far as the IEPLayoutData
is used.
The recommendation is that the GridLayout
should be basically used for views where a stretch/shrink behavior is expected whilst TableWrapLayout
is for editors where the components are integrated in the Eclipse Forms framework. These are the methods of the CompositeFactory
class:
The parameters that have to be specified are the parent composite, the columns’ count for the created layout grid and if these columns have to be with an equal width.
Example
The following example is taken from the above mentioned introduction to SWT layouts. It has been transformed using the EP UI Framework. You can easily compare the sources of the two classes:
final IEpLayoutComposite mainComposite = CompositeFactory
.createGridLayoutComposite(shell, 3, false);
final IEpLayoutData horizontalFill = mainComposite.createLayoutData(
IEpLayoutData.FILL, IEpLayoutData.FILL);
final IEpLayoutData horizontalFill2Cells = mainComposite
.createLayoutData(IEpLayoutData.FILL, IEpLayoutData.FILL, true,
false, 2, 1);
final IEpLayoutData horizontalFillAndStretchHorizontally = mainComposite
.createLayoutData(IEpLayoutData.FILL, IEpLayoutData.FILL, true,
false);
mainComposite.addLabel("Dog's Name:", null);
final Text dogName = mainComposite.addTextField(false,
horizontalFill2Cells);
mainComposite.addLabel("Breed:", null);
final Combo dogBreed = mainComposite.addComboBox(true,
horizontalFillAndStretchHorizontally);
dogBreed.setItems(new String[] { "Collie", "Pitbull", "Poodle",
"Scottie" });
mainComposite.addLabel("Categories", mainComposite.createLayoutData(
IEpLayoutData.CENTER, IEpLayoutData.FILL));
mainComposite.addLabel("Photo:", null);
final Canvas dogPhoto = new Canvas(mainComposite.getSwtComposite(),
SWT.BORDER);
final IEpLayoutData canvasLayoutData = mainComposite.createLayoutData(
IEpLayoutData.FILL, IEpLayoutData.FILL, true, true, 1, 3);
dogPhoto.setLayoutData(canvasLayoutData.getSwtLayoutData());
dogPhoto.addPaintListener(new PaintListener() {
public void paintControl(final PaintEvent event) {
if (UIFrameworkSample.dogImage != null) {
event.gc.drawImage(UIFrameworkSample.dogImage, 0, 0);
}
}
});
// TODO add addList to the UI framework
final List categories = new List(mainComposite.getSwtComposite(),
SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
categories.setItems(new String[] { "Best of Breed", "Prettiest Female",
"Handsomest Male", "Best Dressed", "Fluffiest Ears",
"Most Colors", "Best Performer", "Loudest Bark",
"Best Behaved", "Prettiest Eyes", "Most Hair", "Longest Tail",
"Cutest Trick" });
final IEpLayoutData horizontalAndVerticalFill4Cells = mainComposite
.createLayoutData(IEpLayoutData.FILL, IEpLayoutData.FILL,
false, false, 1, 4);
categories.setLayoutData(horizontalAndVerticalFill4Cells
.getSwtLayoutData());
final Button browse = mainComposite.addPushButton("Browse...",
horizontalFill);
browse.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
final String fileName = new FileDialog(shell).open();
if (fileName != null) {
dogImage = new Image(display, fileName);
}
}
});
final Button delete = mainComposite.addPushButton("Delete",
mainComposite.createLayoutData(IEpLayoutData.FILL,
IEpLayoutData.BEGINNING));
delete.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
if (UIFrameworkSample.dogImage != null) {
UIFrameworkSample.dogImage.dispose();
UIFrameworkSample.dogImage = null;
dogPhoto.redraw();
}
}
});
final IEpLayoutComposite ownerInfo = mainComposite.addGroup(
"Owner Info", 2, false, horizontalFill2Cells);
ownerInfo.addLabel("Name:", null);
final Text ownerName = ownerInfo.addTextField(false,
horizontalFillAndStretchHorizontally);
ownerInfo.addLabel("Phone:", null);
final Text ownerPhone = ownerInfo.addTextField(false,
horizontalFillAndStretchHorizontally);
final IEpLayoutData horizontalEnd3Cells = mainComposite
.createLayoutData(IEpLayoutData.END, IEpLayoutData.FILL, false,
false, 3, 1);
final Button enter = mainComposite.addPushButton("Enter",
horizontalEnd3Cells);
enter.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
System.out.println("\nDog Name: " + dogName.getText());
System.out.println("Dog Breed: " + dogBreed.getText());
System.out.println("Owner Name: " + ownerName.getText());
System.out.println("Owner Phone: " + ownerPhone.getText());
System.out.println("Categories:");
final String cats[] = categories.getSelection();
for (int i = 0; i < cats.length; i++) {
System.out.println("\t" + cats[i]);
}
}
});
GridLayout gridLayout;
new Label(shell, SWT.NULL).setText("Dog's Name:");
dogName = new Text(shell, SWT.SINGLE | SWT.BORDER);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalSpan = 2;
dogName.setLayoutData(gridData);
new Label(shell, SWT.NULL).setText("Breed:");
dogBreed = new Combo(shell, SWT.NULL);
dogBreed.setItems(new String[] { "Collie", "Pitbull", "Poodle",
"Scottie" });
dogBreed.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
final Label label = new Label(shell, SWT.NULL);
label.setText("Categories");
label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
new Label(shell, SWT.NULL).setText("Photo:");
dogPhoto = new Canvas(shell, SWT.BORDER);
gridData = new GridData(GridData.FILL_BOTH);
gridData.widthHint = 80;
gridData.heightHint = 80;
gridData.verticalSpan = 3;
dogPhoto.setLayoutData(gridData);
dogPhoto.addPaintListener(new PaintListener() {
public void paintControl(final PaintEvent event) {
if (dogImage != null) {
event.gc.drawImage(dogImage, 0, 0);
}
}
});
categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
categories.setItems(new String[] { "Best of Breed", "Prettiest Female",
"Handsomest Male", "Best Dressed", "Fluffiest Ears",
"Most Colors", "Best Performer", "Loudest Bark",
"Best Behaved", "Prettiest Eyes", "Most Hair", "Longest Tail",
"Cutest Trick" });
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_FILL);
gridData.verticalSpan = 4;
final int listHeight = categories.getItemHeight() * 12;
final Rectangle trim = categories.computeTrim(0, 0, 0, listHeight);
gridData.heightHint = trim.height;
categories.setLayoutData(gridData);
final Button browse = new Button(shell, SWT.PUSH);
browse.setText("Browse...");
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalIndent = 5;
browse.setLayoutData(gridData);
browse.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
final String fileName = new FileDialog(shell).open();
if (fileName != null) {
EclipseSwtSample.dogImage = new Image(display, fileName);
}
}
});
final Button delete = new Button(shell, SWT.PUSH);
delete.setText("Delete");
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_BEGINNING);
gridData.horizontalIndent = 5;
delete.setLayoutData(gridData);
delete.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
if (EclipseSwtSample.dogImage != null) {
EclipseSwtSample.dogImage.dispose();
EclipseSwtSample.dogImage = null;
dogPhoto.redraw();
}
}
});
final Group ownerInfo = new Group(shell, SWT.NULL);
ownerInfo.setText("Owner Info");
gridLayout = new GridLayout();
gridLayout.numColumns = 2;
ownerInfo.setLayout(gridLayout);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalSpan = 2;
ownerInfo.setLayoutData(gridData);
new Label(ownerInfo, SWT.NULL).setText("Name:");
ownerName = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
ownerName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
new Label(ownerInfo, SWT.NULL).setText("Phone:");
ownerPhone = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
ownerPhone.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final Button enter = new Button(shell, SWT.PUSH);
enter.setText("Enter");
gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
gridData.horizontalSpan = 3;
enter.setLayoutData(gridData);
enter.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
System.out.println("\nDog Name: " + dogName.getText());
System.out.println("Dog Breed: " + dogBreed.getText());
System.out.println("Owner Name: " + ownerName.getText());
System.out.println("Owner Phone: " + ownerPhone.getText());
System.out.println("Categories:");
final String cats[] = categories.getSelection();
for (int i = 0; i < cats.length; i++) {
System.out.println("\t" + cats[i]);
}
}
});
The result of the two approaches is the same except that the UI Framework by default uses the FormToolkit
and therefore takes the more stylish look and feel of the Eclipse Forms.
EP UI Framework | SWT |
---|---|
Understanding the Eclipse Workbench Lifecycle
Commerce Manager utilizes the Eclipse Workbench to create its UI. The Workbench provides events that Commerce Manager can register code against, and Commerce Manager’s com.elasticpath.cmclient.core.CorePlugin
class exposes them for other plugins.
CorePlugin
primarily uses Workbench pre- and post-startup events.
Pre-Startup Events
Pre-startup events are executed before the first Commerce Manager window is opened. At this point, Commerce Manager loads localized messages and strings.
Post-Startup Events
Post-startup events are executed when the window is opened, but before the application’s main event loop starts.
Registering Code for Execution During Pre- and Post-Startup Events
CorePlugin allows you to register code to be executed during pre- and post- startup events.
- To register a pre-startup event, call
CorePlugin.registerPreStartupCallback()
- To register a post-startup event, call
CorePlugin.registerPostStartupCallback()
Both methods accept a Runnable
. You do not need to provide the UI context when registering a Runnable
, as the Runnable
is executed within the UI thread.
Example: Hiding Action Sets on the Main Toolbar Post-Startup
@Override
public void start(final BundleContext context) throws Exception {
super.start(context);
//If change set is disabled or then remove change set toolbar from the CoolBar
CorePlugin.registerPostStartupCallback(new HideActionSetRunnable(changeSetHideCondition, ACTION_SET_ID));
}
The code above registers a Runnable
at bundle startup. When the UI thread executes the Runnable
, it removes the change set action set from the main toolbar.
Adding Menu Items To Commerce Manager’s Main Toolbar
Commerce Manager implements all its toolbars as ToolBar
objects, with the exception of the main (top) toolbar, which is implemented as a ToolBar
. Items, such as icons or buttons, are added to the menu as ContributionItems
.
To add a new menu item to an existing Commerce Manager toolbar, you must extend the existing toolbar using an Eclipse Extension Point and add a new toolbar and add your ContributionItems
to that toolbar. Like all extensions, Toolbar extensions are created in extensions/cm/ext-cm-modules/ext-cm-plugins
.
First, define your new toolbar as a menuContribution
child element of the org.eclipse.ui.menus
extension point in plugin.xml
.
Separators
Adding Seperators has no effect. In order to achieve separation of UI elements, consider grouping items within separate toolbars.
Extending Eclipse Extension Points
For more information on extending Eclipse Toolbars, see the Eclipse Workbench Extension documentation.
To add a contribution item to the main Commerce Manager toolbar, you must do the following in your extension project:
Provide an extension point for
org.eclipse.ui.menus
in your extended plugin’splugin.xml
filePopulate the extension point with
<menuContribution>
and its child elements,<toolbar>
and<command>
<menuContribution>
has one attribute,locationURI
When adding to the main commerce manager toolbar,
locationURI
should betoolbar:org.eclipse.ui.main.toolbar
. For more information onlocationURI
syntax, see Eclipse’s Menu Contributions documentation.<toolbar>
has one attribute,id
The
id
attribute defines the name of the new toolbar you wish to contribute to the main menu bar.<command>
, which represents the behaviour of a menu item in the abstract<command>
is a very flexible element, and is best understood by reading Eclipse Workbench’s<command>
documentation.
The following example adds a contribution item added to the Entitlements perspective.
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="toolbar:org.eclipse.ui.main.toolbar">
<toolbar
id="com.elasticpath.cmclient.core.toolbars.preferences">
<command
commandId="com.elasticpath.extensions.entitlements.handlers.EntitlementCommand"
id="com.elasticpath.extensions.entitlements.handlers.EntitlementCommand"
label="Entitlement Contribution Item"
tooltip="Entitlement Contribution Item">
</command>
</toolbar>
</menuContribution>
</extension>
In order to provide actual implementation of the command, you must also extend the org.eclipse.ui.commands
extension point, where defaultHandler
is a path to the class where your menu item is implemented. The extension point for the commands is needed in order to provide implementation. The id
in this case matches the command id
.
<extension point="org.eclipse.ui.commands">
<command
id="com.elasticpath.extensions.entitlements.handlers.EntitlementCommand"
defaultHandler="com.elasticpath.extensions.entitlements.handlers.EntitlementCommand"
name="Open Entitlement Stuff">
</command>
</extension>
Exceptions
When adding contribution items to menus, there are two exceptions to the rules presented above.
toolbar:org.eclipse.ui.trim.command2
RAP does not render
toolbar:org.eclipse.ui.trim.command2
– the right trim area – of the toolbar correctly. If attempting to contribute UI elements totoolbar:org.eclipse.ui.trim.command2
, use Elastic Path’s alternative,toolbar:com.elasticpath.cmclient.core.toolbars.right
instead. This uses Elastic Path’sContributionLoader
class to extract all the items contributed to a specific toolbar URI and load them intoToolBarManager
correctly.Perspective Toolbar
In order to add a new item to the Perspective toolbar the following id must be used as the
locationURI: com.elasticpath.cmclient.core.toolbars.activities
Abstract Dialog Component
AbstractEPDialog
is meant to be used for all dialogs that have title bar area consisting of a title, description and image. It provides utility methods for creating the more commonly used buttons like OK, Save, Set, Confirm and Cancel. By default a combination of Save and Cancel buttons is configured.
AbstractEPDialog
How to use AbstractEPDialog
should be extended and the following abstract methods implemented when necessary:
/**
* Populates the controls for the contents.
*/
protected abstract void populateControls();
/**
* Binds the controls for the contents.
*/
protected abstract void bindControls();
/**
* Creates the controls that have to be displayed in the client area of the dialog.
*
* @param dialogComposite the EP layout composite to be used
*/
protected abstract void createEpDialogContent(IEpLayoutComposite dialogComposite);
/**
* Gets the title of the dialog displayed in the title area.
*
* @return String or null if none
*/
protected abstract String getTitle();
/**
* Gets the description of the dialog displayed in the title area.
*
* @return String or null if none
*/
protected abstract String getInitialMessage();
/**
* Gets the title image displayed in the title area.
*
* @return Image or null if none
*/
protected abstract Image getTitleImage();
/**
* Should return the dialog window title.
*
* @return String or null if none
*/
protected abstract String getWindowTitle();
/**
* Should return the dialog window image.
*
* @return Image or null if none
*/
protected abstract Image getWindowImage();
For values that should not be displayed a simple return of null value will leave the title, image or description fields empty.
Creating a custom dialog implies the usage of the EP UI Framework as the main tool to create and manage the UI controls.
For creating custom buttons or to change the default buttons a specific method has to be overridden. The following is an example of creating a custom labeled OK button along with a Cancel one.
protected void createButtonsForButtonBar(final Composite parent) {
createEpOkButton(parent, "My Button", null);
createEpCancelButton(parent);
}
Hadling OK button click event is done in okPressed()
method. Cancel button event closes the dialog by default but this behaviour can be changed by overriding cancelPressed()
method.
For creating one of the predefined button sets you can do the following:
protected void createButtonsForButtonBar(final Composite parent) {
createEpButtonsForButtonsBar(ButtonsBarType.CONFIRM, parent);
}
AbstractEpDialog
for?
What not to use Do not use AbstractEpDialog for displaying dialogs that are a part of the standard SWT API:
- Errors, warnings, and informational messages
- Question/confirmation dialogs
All of these can be displayed using the MessageDialog
API:
MessageDialog.openError(...)
MessageDialog.openWarning(...)
MessageDialog.openInformation(...)
MessageDialog.openQuestion(...)
MessageDialog.openConfirm(...)
Example
For reference you can take a look at the numerous dialogs implemented on top of the AbstractEpDialog
(e.g. CustomerAddEditAddressDialog
, VirtualCatalogDialog
, etc.)
DateTime
Component
The date and time component uses the implementation of a Nebula project widget, CDateTime
. This widget provides a text field that is a combo box and a popup date and time selector. The popup window is integrated with an SWT Text object, which supports the following behaviors:
- Allows the date and time component to be bound using the binding framework.
- Prevents setting a border style of the widget.
- Prevents an issue with the tab navigation when no date is set.
DateTime
How to use Standalone
EpControlFactory epControlFactory = new EpControlFactory(); IEpDateTimePicker picker = epControlFactory.createDateTimeComponent(final Composite parentComposite, final int style, final EpState epState);
Using the UI framework
IEpLayoutComposite epComposite = ... IEpDateTimePicker picker = epComposite.addDateTimeComponent(int style, EpState epState, IEpLayoutData data);
The style can be either IEpDateTimePicker.STYLE_DATE
or IEpDateTimePicker.STYLE_DATE_AND_TIME
.
Useful Methods
setFormatter(DateFormat)
For displaying the correct date/time string a
DateFormat
is used. If no formatter has been set the default ones are used -DateFormat.getDateInstance()
for dates andDateFormat.getDateTimeInstance()
for date and time.setDate(Date)
This method initializes the date (if null the current date will be displayed and the text field will be empty)
getDate()
Returns the Date object representing the selected date.
open(Control, boolean)
Used only if the date/time component has to be invoked from another UI widget. It is used currently only for the table in-line editing
How to bind it using the binding framework
The recommended way of doing that is to use the utility method defined in the IEpDateTimePicker
interface:
//com.elasticpath.cmclient.core/src/main/java/com/elasticpath/cmclient/core/ui/framework/IEpDateTimePicker.java
EpValueBinding bind(DataBindingContext context, IValidator validator, Object target, String fieldName);
All that has to be provided is the binding context, validator (most probably from EpValidatorFactory
), the object to be bound and the respective field name.
The other way round is to use the IEpDateTimePicker.getSwtText()
in order to bind the text field to the respective object field. There are predefined validators in EpValidatorFactory
class:
DATE
DATE_REQUIRED
DATE_TIME
DATE_TIME_REQURED
List Viewer Component
This component represents a list of items. It abstracts the usage of the more native Eclipse TableViewer and customizes the UI to look like a native list control. The main problem with the original Eclipse List control is that it cannot have images.
ListViewer
How to use It can be created either from IEpLayoutComposite
or standalone using the EpControlFactory
. The method names to be used are as follows:
IEpListViewer EpControlFactory.createListViewer(Composite parentComposite, String listLabel, boolean multiSelection, EpState epState)
//or
IEpLayoutComposite.addListViewer(final String listLabel, final boolean multiSelection, final EpState epState, final IEpLayoutData data)
After creating an instance of the list viewer the content and label providers must be set using the respective setters on the interface. If the list is meant to be editable the org.eclipse.jface.viewers.EditingSupport
implementation has to be applied too. Initializing the list viewer control is done by calling IEpListViewer.setInput(Object)
.
Example
The EP List viewer is mainly used in AbstractEpDualListBoxControl
which is a dual list viewer part that has buttons in between the two list boxes. The buttons are used for adding elements from the left list box to the right and removing them vice versa.
Tab Folder Component
The EPTabFolder component abstracts the Eclipse’s CTabFolder UI control. The tab folder basically represents a sequence of tabs of which only one is active at a time.
EPTabFolder
How to use Currently the tab folder component can be created from the IEpLayoutComposite
.
IEpTabFolder IEpLayoutComposite.addTabFolder(final IEpLayoutData data)
The newly created instance allows adding tab items. Those tab items are abstracted by the IEpLayoutComposite
. This way the developer can directly code the UI controls for each tab using the provided instance of IEpLayoutComposite
interface.
There are two methods for adding a new tab:
IEpLayoutComposite IEpTabFolder.addTabItem(String tabName, Image image, int tabIndex)
IEpLayoutComposite IEpTabFolder.addTabItem(String tabName, Image image, int tabIndex, int numColumns, boolean equalWidthColumns);
The difference between them is that the first one creates a composite that has only 1 column.
Example
In this example the mainComposite
that is of type IEpLayoutComposite
is populated by a tab folder and its tab items. This is the code representing the merchandising associations tab. The tab items are the catalogs the product belongs to. The view part is responsible for the contents of the respective Catalog tab item.
//com.elasticpath.cmclient.catalog/src/main/java/com/elasticpath/cmclient/catalog/editors/product/ProductMerchandisingAssociationsPage.java
final IEpLayoutData tableFolderData = mainComposite.createLayoutData(IEpLayoutData.FILL, IEpLayoutData.FILL, true, true);
PolicyActionContainer tabContainer = addPolicyActionContainer("tab"); //$NON-NLS-1$
this.tabFolder = mainComposite.addTabFolder(tableFolderData);
int index = 0;
for (Catalog catalog : getSortedCatalogs()) {
Image image = null;
if (catalog.isMaster()) {
image = CatalogImageRegistry.getImage(CatalogImageRegistry.CATALOG_MASTER);
} else {
image = CatalogImageRegistry.getImage(CatalogImageRegistry.CATALOG_VIRTUAL);
}
final IEpLayoutComposite catalogTabItem = this.tabFolder.addTabItem(catalog.getName(), image, index , 1, false);
catalogTabItem.getSwtComposite().setLayoutData(tableFolderData.getSwtLayoutData());
ProductMerchandisingAssociationsViewPart merchAssociationViewPart =
new ProductMerchandisingAssociationsViewPart(catalog, (ProductEditor) getEditor());
tabContainer.addDelegate(merchAssociationViewPart);
merchAssociationViewPart.createControls(catalogTabItem, tableFolderData);
tabViewParts.put(index, merchAssociationViewPart);
getEditor().addPropertyListener(merchAssociationViewPart);
index++;
}
this.tabFolder.getSwtTabFolder().addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
tabViewParts.get(tabFolder.getSelectedTabIndex()).populateControls();
}
});
this.tabFolder.setSelection(0);
Table Viewer Component
The EP table viewer abstracts the Eclipse’s TableViewer
and TableColumn
components.
IEpTableViewer
How to use An instance of IEpTableViewer
can be obtained from the IEpLayoutComposite
or EpControlFactory
:
IEpTableViewer IEpLayoutComposite.addTableViewer(boolean multiSelection, EpState epState, IEpLayoutData data)
IEpTableViewer EpControlFactory.createTableViewer(final Composite parentComposite, final int style, final EpState epState)
Usually a table has to have at least one column. Columns can be added by calling
IEpTableColumn IEpTableViewer.addTableColumn(String headerText, int initialWidth)
The interface IEpTableColumn
represents a column in the table.
There are two modes for an EP table viewer depending on the EpState (EDITABLE
, READ_ONLY
, DISABLED
).
If the table is created in read-only mode the label provider can be set directly on the IEpTableViewer
instance. The provided label provider will be responsible for checking which column the label should be provided for and return it accordingly.
If the table created is in EDITABLE
state then each column has to have its own column label provider and editing support implementations. Of course editing support can be omitted in case it is not needed.
The look and feel of the table viewer is predefined and is dependent on the EpState
value supplied at creation time.
Example
This example is extracted from AddSkuWizardPage2
class. It shows the way the new SKU wizard handles the attributes values that have to be set to the SKU object model. An IEpTableViewer
is created and a few columns added. The editing support is needed so that we have the value column editable when the user clicks over it. The AttributeEditingSupport
class extends the org.eclipse.jface.viewers.EditingSupport
.
//com.elasticpath.cmclient.catalog/src/main/java/com/elasticpath/cmclient/catalog/wizards/sku/AddSkuWizardPage2.java
this.attributesTableViewer = mainComposite.addTableViewer(false, EpState.EDITABLE, tableLayoutData);
final GridData tableLayoutData2 = (GridData) attributesTableViewer.getSwtTable().getLayoutData();
tableLayoutData2.heightHint = TABLE_HIGH_HINT;
tableLayoutData2.widthHint = TABLE_WIDTH_HINT;
//getSection().setLayoutData(getLayoutData());
// the name column content of the attribute table
final IEpTableColumn nameColumn = this.attributesTableViewer
.addTableColumn(
CatalogMessages.ProductEditorAttributeSection_TableColumnTitle_Name,
200);
// The attribute type column content of the attribute table
final IEpTableColumn typeColumn = this.attributesTableViewer
.addTableColumn(
CatalogMessages.ProductEditorAttributeSection_TableColumnTitle_Type,
80);
// The attribute required column content of the attribute table
final IEpTableColumn requiredColumn = this.attributesTableViewer
.addTableColumn(
CatalogMessages.ProductEditorAttributeSection_TableColumnTitle_Required,
60);
// The attribute required column content of the attribute table
final IEpTableColumn multiLanguageColumn = this.attributesTableViewer
.addTableColumn(
CatalogMessages.ProductEditorAttributeSection_TableColumnTitle_MLang,
90);
// The attribute value column content of the attribute table
final IEpTableColumn valueColumn = this.attributesTableViewer
.addTableColumn(
CatalogMessages.ProductEditorAttributeSection_TableColumnTitle_Value,
300);
final AttributesLabelProviderUtil labelProviderUtil = new AttributesLabelProviderUtil(EpState.EDITABLE);
labelProviderUtil.setNameColumnLabel(nameColumn);
labelProviderUtil.setTypeColumnLabel(typeColumn);
labelProviderUtil.setRequiredColumnLabel(requiredColumn);
labelProviderUtil.setMultiLanguageColumnLabel(multiLanguageColumn);
labelProviderUtil.setValueColumnLabel(valueColumn);
// add EditSupport to the attribute value column
valueColumn.setEditingSupport(new AttributeEditingSupport(this.attributesTableViewer, this.getProductSku()));
Tree Viewer Component
EP tree viewer represents data in a tree-table like structured way using the Eclipse’s TreeViewer
JFace component.
IEpTreeViewer
How to use Like all the other components it can be created through the IEpLayoutComposite
instance or the EpControlFactory
:
IEpTreeViewer addTreeViewer(boolean multiSelection, EpState epState, IEpLayoutData data)
IEpTreeViewer createTreeViewer(Composite parentComposite, boolean multiSelection, EpState epState)
If you add more than one column to table, only the first column will be a tree. The rest will represent other data for the tree nodes. This is achieved by calling the addColumn()
method as many times as required:
IEpTreeColumn addColumn(String headerText, int initialWidth)
The interface IEpTreeColumn
allows for setting the label provider and editing support to the column.
The major difference with the table viewer is the content provider type. It has to be an instance of IStructuredContentProvider
. This interface allows defining the tree and all its nodes. Implementing this interface and setting it to a tree viewer is followed by setting the input object. It has to be a collective object that will be able to return the root elements of the tree. This object is then passed to the structured content provider that has to cast the object and extract the root elements in getElements(Object inputObject)
and return them as an array. In getChildren(Object treeNode)
one should expect to receive the root elements returned on getElements(...)
and all the children returned by previous calls to getChildren(...)
method. That way all tree nodes should be visited and the tree created.
Example
This example is an extract from RolePermissionsDualListbox
. This class is responsible for defining role permissions when creating a new role in Configuration area (User Roles). Adding the tree and setting the content and label providers defines the tree view.
//com.elasticpath.cmclient.admin.users/src/main/java/com/elasticpath/cmclient/admin/users/wizards/RolePermissionsDualListbox.java
//
// Second Row
//
// List box
availableEpTreeViewer = controlPane.addTreeViewer(true, EpState.READ_ONLY, fillData);
availableEpTreeViewer.setContentProvider(new AvailablePermissionsContentProvider());
availableEpTreeViewer.setLabelProvider(new AvailablePermissionsLabelProvider());
availableEpTreeViewer.getSwtTreeViewer().setSorter(new PermissionsNodeSorter());
For populating the tree in populateControls
, call setInput()
as follows:
availableEpTreeViewer.setInput(getAvailable());