The purpose of the article is to demonstrate how fast and easy it can be to build an Eclipse client to a database using the Fishbolt technology.
There is a complete sample of building a hibernate model with a couple of data objects and several of the Eclipse views, editors, wizards and actions. The technology assumes a unique kind of data object (not unlike a Javabean). Such original kinds of data objects allows you to evaluate data structure errors at the compilation stage.
Table of contents
Eclipse based database client with the hibernate technology
Data Model plug-in
Plug-in creation
Data object classes and its managers creation
Data model class declaration
Configuring hibernate
Calculated fields
Changes in the plug-in manifest
The resulting plug-in
Database structure creation
UI plug-in
Data object wizards
Data object editor
Change data field value dialog
Department-Employee tree
Employees table
Employee search panel
Application UI
Additional resources
The example sources like other examples are prepared for
download here.
The required plug-ins update site URL is
http://fishbolt.org/eclipse/update.
A zipped archive of the update site can be found
here.
Data Model plug-in
The separated Eclipse plug-in creation is described in the following section. The plug-in will contain the data model declaration. It is a good practice to separate data model from user interface.
Plug-in creation
Start by adding a dependency after the plug-in creation:

Add the following line to the MANIFEST.MF file (to use single class loader for work with hibernate libraries):
Eclipse-RegisterBuddy: org.fishbolt.model.hibernate.annotations
Data object classes and its managers creation
/**
* Data object presenting Department
*/
@DisplayLabel("Department")
@ImageResource("Department.gif")
@Entity
@Tuplizer(impl = CompanyModelTuplizer.class)
@AccessType("org.fishbolt.model.hibernate.FieldAccessor")
public class Department extends HDataObject<DepartmentManager> {
@Id
@GeneratedValue
@DisplayLabel("Identity")
public final static FieldDeclaration<Integer> id =
new FieldDeclaration<Integer>(Department.class);
@ObjectPresentationField
@Column(unique=true, nullable=false)
@DisplayLabel("Name")
@Width(250)
public final static FieldDeclaration<String> name =
new FieldDeclaration<String>(Department.class);
@DisplayLabel("Employees")
@Relation(inverse="department")
@OneToMany(targetEntity=Employee.class)
@JoinColumn(name= "department")
public final static FieldDeclaration<Set<Employee>> employees =
new FieldDeclaration<Set<Employee>>(Department.class);
public Department(DepartmentManager manager) {
super(manager);
}
public Department() {
super();
}
}
“Department” data object manager:
/**
* Manager class for {@link Department} data object.
*/
public class DepartmentManager extends HDataObjectManager<Department,Integer>{
/**
* Constructor inherited from the super class
*/
public DepartmentManager(IDataModel dataModel, ObjectDescriptor<?,?> objectDescriptor){
super(dataModel, objectDescriptor);
}
/**
* Searches for a Department by its name
* @param name - the name of the Department to search for
* @return Department r<code>null</code>
*/
public Department findDepartment(String name){
String hql = "from Department where name=?";
QueryUniqueResultCommand<Department> cmd =
new QueryUniqueResultCommand<Department>(hql);
cmd.setParameters(new Parameter(name));
return this.getModel().processCommand(cmd);
}
}
“Employee” data object:
/**
* Data object presenting Employee
*/
@DisplayLabel("Employee")
@ImageResource("Employee.gif")
@Entity
@Tuplizer(impl = CompanyModelTuplizer.class)
@AccessType("org.fishbolt.model.hibernate.FieldAccessor")
public class Employee extends HDataObject<EmployeeManager> {
@Id
@GeneratedValue
@DisplayLabel("Identity")
public final static FieldDeclaration<Integer> id =
new FieldDeclaration<Integer>(Employee.class);
@Transient
@ObjectPresentationField
@DisplayLabel("Name")
@Width(250)
public final static FieldDeclaration<String> name =
new FieldDeclaration<String>(Employee.class);
@Column(nullable=false)
@DisplayLabel("First Name")
public final static FieldDeclaration<String> firstName =
new FieldDeclaration<String>(Employee.class);
@Column(nullable=false)
@DisplayLabel("Last Name")
public final static FieldDeclaration<String> lastName =
new FieldDeclaration<String>(Employee.class);
@DisplayLabel("Phone Number")
public final static FieldDeclaration<String> phoneNumber =
new FieldDeclaration<String>(Employee.class);
@SimpleDateFormatPresentation("dd/MM/yyyy")
@DisplayLabel("Birthday")
public final static FieldDeclaration<Date> birthday =
new FieldDeclaration<Date>(Employee.class);
@DisplayLabel("Salary")
@Column(nullable=false)
@DecimalFormatPresentation("#,##0.00")
@PresentationDecorator(prefix="$ ")
public final static FieldDeclaration<BigDecimal> salary =
new FieldDeclaration<BigDecimal>(Employee.class);
@DisplayLabel("Health")
@NumberFormatPresentation(NumberFormatInstance.percent)
public final static FieldDeclaration<Double> health =
new FieldDeclaration<Double>(Employee.class);
@DisplayLabel("Department")
@Relation(inverse="employees")
@ManyToOne(optional=false)
@JoinColumn(name="department")
public final static FieldDeclaration<Department> department =
new FieldDeclaration<Department>(Employee.class);
public Employee(EmployeeManager manager) {
super(manager);
}
public Employee() {
super();
}
}
“Employee” data object manager:
/**
* Manager class for {@link Employee} data object.
*/
public class EmployeeManager extends HDataObjectManager<Employee,Integer>{
/**
* Constructor inherited from the super class
*/
public EmployeeManager(IDataModel dataModel, ObjectDescriptor<?,?> objectDescriptor){
super(dataModel, objectDescriptor);
}
/**
* Searches for an employee among all employees of a company
* @param firstName - employee's first name
* @param lastName - employee's last name
* @return<code>List</code> of employees
*/
public List<Employee> findEmployee(String firstName,String lastName){
String hql = "from Employee where firstName=? and lastName = ?";
QueryListCommand<Employee> cmd =
new QueryListCommand<Employee>(hql);
cmd.setParameters( new Parameter(firstName), new Parameter(lastName));
return this.getModel().processCommand(cmd);
}
/**
* Searches for an employee in a Department
* @param firstName - employee's first name
* @param lastName - employee's last name
* @param department
* @return<code>List</code> of employees
*/
public List<Employee> findEmployee(String firstName,String lastName, Department department){
String hql = "from Employee where firstName=? and lastName=? and department=?";
QueryListCommand<Employee> cmd = newQueryListCommand<Employee>(hql);
cmd.setParameters(
new Parameter(firstName),
new Parameter(lastName),
new Parameter(department));
return this.getModel().processCommand(cmd);
}
}
Data model class declaration
/**
* Company model class
*/
public class CompanyModel extends DataModel {
public final static
ObjectDescriptor<EmployeeManager,Employee> employee =
newEObjectDescriptor<EmployeeManager,Employee>(CompanyModel.class);
public final static
ObjectDescriptor<DepartmentManager,Department> department =
newEObjectDescriptor<DepartmentManager,Department>(CompanyModel.class);
public static ModelDescriptor getDescriptor(){
return CompanyModel.Department.getModelDescriptor();
}
private static CompanyModel instance;
public static CompanyModel getInstance(){
return (instance == null) ?
instance = new CompanyModel(getDescriptor()) : instance;
}
private CompanyModel(ModelDescriptor modelDescriptor) {
super(modelDescriptor);
}
}
Configuring hibernate
Let’s create the Tuplizer-class (mentioned at co-named annotation in data objects)
public class CompanyModelTuplizer extends DataObjectTuplizer {
/**
* Constructor inherited from the super class
*/
public CompanyModelTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
super(entityMetamodel, mappedEntity);
}
@Override
protected ModelDescriptor getModelDescriptor() {
return CompanyModel.getDescriptor();
}
}
hibernate.cfg.xml creation
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
org.hibernate.dialect.PostgreSQLDialect
</property>
<property name="hibernate.connection.driver_class">
org.postgresql.Driver
</property>
<property name="hibernate.connection.url">
jdbc:postgresql://localhost/company
</property>
<property name="hibernate.connection.username">
postgres
</property>
<property name="hibernate.connection.password">
********
</property>
<mapping class="example.model.objects.Department"/>
<mapping class="example.model.objects.Employee"/>
</session-factory>
</hibernate-configuration>
Calculated fields
The “Employee” data object contains name filed.
The filed is calculated and doesn’t mapped to the database as a result.
The algorithm of the filed value evaluation implemented bellow:
public class EmployeeFullNameCalculation implements IFieldCalculation<String> {
public FieldPath[] getInfluencingPaths(FieldDescriptor<String> dependent) {
return new FieldPath[]{
new FieldPath(true, CompanyModel.employee,Employee.firstName),
new FieldPath(true, CompanyModel.employee,Employee.lastName)
};
}
public String evaluateValue(IDataField<String> toEvaluate) {
Employee employee = (Employee)toEvaluate.getDataObject();
return ModelUtil.getValue(employee,Employee.firstName)+
" " + ModelUtil.getValue(employee,Employee.lastName);
}
}
Let’s bind in code the algorithm and data field
public class CompanyCalculationProviderFactory extends FieldCalculationProviderFactorySafe{
/**
* Binds calculated fields with calculation classes
*/
@Override
protected void bindCalculations() {
//binding <code>Employee.name</code> with <code>EmployeeFullNameCalculation</code>
bindCalculation(CompanyModel.employee,Employee.name, new EmployeeFullNameCalculation());
}
}
Changes in the plug-in manifest
Let’s register factory providers – declare extension of the ModelAdapterFactory point:
Hence the plugin.xml looks in the following way:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension
point="org.fishbolt.model.ModelAdapterFactory">
<model class="example.model.CompanyModel">
<factory class="example.model.calculations.CompanyCalculationProviderFactory"/>
<factory class="org.fishbolt.model.memory.ext.compare.ComparatorProviderFactory"/>
<factory class="org.fishbolt.model.memory.ext.listener.ListenerRegistryAdapterFactory"/>
<factory class="org.fishbolt.model.ext.width.WidthProviderFactory"/>
<factory class="org.fishbolt.model.ext.image.ObjectImageProviderFactory"/>
<factory class="org.fishbolt.model.hibernate.ext.presenter.HPresenterProviderFactory"/>
<factory class="org.fishbolt.model.hibernate.ext.calculate.HInfluencingFieldProviderFactory"/>
<factory class="org.fishbolt.model.memory.ext.state.FieldStateFactory"/>
<factory class="org.fishbolt.model.hibernate.ext.state.HObjectStateFactory"/>
<factory class="org.fishbolt.model.hibernate.ext.state.HFieldDescriptorStateFactory"/>
<factory class="org.fishbolt.model.hibernate.ext.state.HObjectDescriptorStateFactory"/>
<factory class="org.fishbolt.model.hibernate.provider.field.HFieldManagerProviderFactory"/>
<factory class="org.fishbolt.model.hibernate.provider.object.HObjectManagerProviderFactory"/>
<factory class="org.fishbolt.model.memory.ext.label.LabelProviderFactory"/>
<factory class="org.fishbolt.model.hibernate.provider.HModelProviderFactory"/>
<factory class="org.fishbolt.model.hibernate.annotations.provider.AnnotationConfigurationProviderFactory"/>
<factory class="org.fishbolt.model.hibernate.ext.lo.HLargeObjectProviderFactory"/>
</model>
</extension>
</plugin>
Let’s export packages:
And add the driver library:
The resulting plug-in
Database structure creation
Let’s create the “company” database with the help of the
Data Base Admin console. Database server (Postgres), database name, login and password
are defined in the hibernate.cfg.xml file
The class bellow generates database structure.
It’s necessary to change temporary the type of the last field descriptor
(CompanyModel.department) from to
EObjectDescriptor
ObjectDescriptor before the class execution.
/**
* Use the class to generate database structure. The call
* erases data from database (drops tables with data and creates empty tables).
*/
public class CompanyDBSchema {
/**
* To make it working you need to change <code>
* new <b>E</b>ObjectDescriptor</code> with
* the<code>new ObjectDescriptor</code> for the last
* static field - {@link CompanyModel#department}.
* (don't forget to return it back)
*/
public static void main(String[] args){
ModelDescriptor descriptor = CompanyModel.getDescriptor();
// Explicit adapter registration is necessary because
// extension points don't work for plain java application
AdapterFactoryManager manager = descriptor.getAdapterFactoryManager();
// the adapter classes are taken from the
// ModelAdapterFactory extension point (see plugin.xml)
manager.register(new ComparatorProviderFactory());
manager.register(new ListenerRegistryAdapterFactory());
manager.register(new WidthProviderFactory());
manager.register(new ObjectImageProviderFactory());
manager.register(new HPresenterProviderFactory());
manager.register(new HInfluencingFieldProviderFactory());
manager.register(new FieldStateFactory());
manager.register(new HObjectStateFactory());
manager.register(new HFieldDescriptorStateFactory());
manager.register(new HObjectDescriptorStateFactory());
manager.register(new HFieldManagerProviderFactory());
manager.register(new HObjectManagerProviderFactory());
manager.register(new LabelProviderFactory());
manager.register(new HModelProviderFactory());
manager.register(new CompanyCalculationProviderFactory());
manager.register(new AnnotationConfigurationProviderFactory());
manager.register(new HLargeObjectProviderFactory());
// executing of the SchemaExport-hibernate tool
ConfigurationProvider provider = descriptor.getAdapter(ConfigurationProvider.class);
SchemaExport task = new SchemaExport(provider.getConfiguration());
task.create(true, true);
}
}
The following SQL statemets were generated and executed by the class:
alter table Employee drop constraint FK4AFD4ACE8385E2C7
drop table Department
drop table Employee
drop sequence hibernate_sequence
create table Department (id int4 not null, name varchar(255) not null unique, primary key (id))
create table Employee (id int4 not null, birthday timestamp, firstName varchar(255) not null,
health float8, lastName varchar(255) not null, phoneNumber varchar(255),
salary numeric(19, 2) not null, department int4 not null, primary key (id))
alter table Employee add constraint FK4AFD4ACE8385E2C7 foreign key (department) references Department
create sequence hibernate_sequence
UI plug-in
Let’s create UI plug-in and add the dependencies
As it shown, the created data
model plug-in (example.org.fishbolt.model.hibernate.annotations) is among the dependencies.
Data object wizards
Let’s create wizard clasess. The “Employe” data object wizard listing is bellow:
/**
* Wizard for adding new employees
*/
public class NewEmployeeWizard extends ObjectNewWizard {
public NewEmployeeWizard() {
// indicating the descriptor of a data object
// whose instances will be created by the wizard
super(CompanyModel.employee);
}
@Override
protected IDataModel getDataModel(IWorkbench workbench,
IStructuredSelection selection) {
// providing a reference to the data model
// to which new Employee instances will be added
return CompanyModel.getInstance();
}
@SuppressWarnings("unchecked")
@Override
public void init(IWorkbench workbench, IStructuredSelection selection){
super.init(workbench, selection);
// Setting a default value to Employee.department
Object selectionObject = selection.getFirstElement();
if (selectionObject instanceof Department)
ModelUtil.setValue(this.wizardObject, Employee.department,(Department)selectionObject);
String name = LabelProvider.getDisplayLabel(CompanyModel.employee);
// adding pages for step-by-step creation of Employee instances
this.addPage(
new ObjectSimpleWizardPage(name,name,null,
Employee.firstName,
Employee.lastName,
Employee.department,
Employee.phoneNumber));
this.addPage(
new ObjectSimpleWizardPage(name,name,null,
Employee.birthday,
Employee.salary,
Employee.health));
}
}
Let’s register corresponding extension
The first page of the “Employee” wizard:
Let’s add UI action which opens wizard to create new “Employee” data object
public class OpenNewEmployeeWizardAction extends OpenNewWizardAction {
@SuppressWarnings("unchecked")
public OpenNewEmployeeWizardAction(ViewerController controller) {
super(controller, "New Employee...","Creates a new Employee");
}
@Override
public INewWizard getNewWizard() {
return new NewEmployeeWizard();
}
@Override
public void updateEnable() {
this.setEnabled(getActionObject() instanceof Department);
}
}
Data object editor
Let’s create editor factories for the data objects
/**
* EditorFactory for <code>Employee</code>s
*/
public class EmployeeEditorFactory extends EditorFactory {
EmployeeEditorFactory() {
// Indicating an Employee object via its descriptor
// and creating editorpages
super(CompanyModel.employee,
new SimpleEditorPageFactory(
"Personal information",
Employee.firstName,
Employee.lastName,
Employee.phoneNumber,
Employee.birthday,
Employee.health),
new SimpleEditorPageFactory(
"Department information",
Employee.department,
Employee.salary)
);
}
}
/**
* EditorFactoryfor<code>Department</code>s
*/
public class DepartmentEditorFactory extends EditorFactory {
DepartmentEditorFactory() {
// Indicating a Department object via its descriptor
// and creating editor pages
super(CompanyModel.department,
new SimpleEditorPageFactory(
LabelProvider.getDisplayLabel(CompanyModel.department),
Department.name)
);
}
}
It’s also necessary to create editor provider class and register it:
public class CompanyEditorProvider extends EditorProvider {
public CompanyEditorProvider(){
register(new DepartmentEditorFactory());
register(new EmployeeEditorFactory());
}
}
And to declare editor:
Created Employee editor is shown on the picture:
Let’s add UI action which opens editor for the data objects
public class OpenInEditorAction extends OpenEditorAction {
@SuppressWarnings("unchecked")
public OpenInEditorAction(ViewerController controller) {
super("example.model.eclipse.DataObjectEditor", controller);
}
}
Let’s add UI action which opens editor for the data
objects in a separate perspective for example
public class OpenInEditorPerspectiveAction extends OpenEditorPerspectiveAction {
@SuppressWarnings("unchecked")
public OpenInEditorPerspectiveAction(ViewerController controller) {
super("example.model.eclipse.perspectives.ObjectEditorPerspective",
"example.model.eclipse.DataObjectEditor", controller);
}
}
Change data field value dialog
Let’s look at the class of a dialog that allows a user to move an Employee from one Department to another:
/**
* Dialog that moves an Employee from one Department to another
*/
public class ChangeDepartmentDialog extends Dialog implements IWidgetsContext{
private Employee employee;
private ContextControllerBinder contextBinder;
public ChangeDepartmentDialog(Shell parentShell,Employee employee) {
super(parentShell);
this.employee = employee;
}
/**
* Returns ContextControllerBinder that binds
* user interface components with data model components
* through controllers
*/
public ContextControllerBinder getContextBinder() {
return contextBinder == null ?
contextBinder = new ContextControllerBinder(this) : contextBinder;
}
/**
* Creates dialog's contents
* and binds user interface components with data model components
*/
@Override
protected Control createDialogArea(Composite parent)
{
// dialog title
parent.getShell().setText(PresenterProvider.getPresentation(employee));
Composite result = new Composite(parent, SWT.NONE);
result.setLayout(new GridLayout(2, true));
Label decription = new Label(result, SWT.NULL);
decription.setLayoutData(new GridData(GridData.FILL,GridData.FILL,true,true,2,1));
decription.setText("To move the employee to another Department, " +
"select the Department and press OK.");
// Label presenting the data object field
Label label = new Label(result, SWT.NULL);
label.setLayoutData(new GridData());
// Combo presenting data field values
Combo combo = new Combo(result, SWT.BORDER | SWT.DROP_DOWN);
combo.setLayoutData(new GridData(GridData.FILL,GridData.CENTER,true,false));
ContextControllerBinder binder = getContextBinder();
// binding Label to FieldDescriptor
// (the controller that is responsible for interaction
// between Label and FieldDescriptor is created automatically)
binder.bind(label, CompanyModel.employee.getFieldDescriptor(Employee.department));
// binding data field to Combo
// (the controller that is responsible for interaction
// between data field and Combo is created automatically)
binder.bind(combo, employee.getDataField(Employee.department));
return result;
}
/**
* Reacts to changes resulted from user's actions on the UI
* components (controls) that were bound to data model
* components using ContextControllerBinder
*/
@SuppressWarnings("unchecked")
public void contextWidgetChanged(EditableWidgetController<Widget, Object, Object> controller,
PresentationException exception) {
if (exception!= null){
MessageDialog.openError(this.getShell(),"The value is incorrect.","Please specify a correct value.");
return;
}
Collection<ValidationMessage<IDataObject, Severity>> problems = employee.validate(null);
if (problems.isEmpty()) return;
showProblems(problems);
employee.refresh();
}
/**
* Shows information about the data object problems
* @param problems
*/
protected void showProblems(Collection<ValidationMessage<IDataObject, Severity>> problems){
StringBuffer msg = new StringBuffer();
for (ValidationMessage<IDataObject, Severity> problem : problems){
msg.append(problem.getDescription());
msg.append("\\;n");
}
MessageDialog.openError(this.getShell(),"The value is incorrect.",msg.toString());
}
/**
* Cancel button handler
*/
@Override
protected void cancelPressed() {
employee.refresh();
super.cancelPressed();
}
/**
* OK button handler
*/
@Override
protected void okPressed() {
employee.store();
super.okPressed();
}
}
The dialog for moving an employee to another Departments looks something like this:
Department-Employee tree
Let’s create the UI-tree element which shows all the Departments with employees:
/**
* Creates a view that contains
* the tree of Departments and employees
*/
public class DepartmentEmployeesView extends ViewPart {
private TreeViewerController treeController = null;
@Override
public void createPartControl(Composite parent) {
// creating a controller for TreeViewer
treeController = new TreeViewerController(parent);
// Setting layout
GridData data = new GridData(GridData.FILL,GridData.FILL,true,true);
treeController.getViewer().getControl().setLayoutData(data);
// Using ColumnData to wrap up data objects to be represented in tree nodes.
// Data objects are specified through their descriptors
treeController.setColumnProvider(
new ColumnProvider(
new ColumnData(CompanyModel.department).add(CompanyModel.employee)));
// Wrapping data in TreeDataObjects and passing it to the controller.
// To put it in more details:
// - indicating data objects to be represented in parent nodes.
// In this case, these are objects of the Deparment type.
// The Department objects are indicated through their manager (DepartmentManager).
// - indicating data objects to be represented in child nodes.
// They are indicated through a bidirectional association.
// In this case, the bidirectional association is expressed by Department.employees
CompanyModel model = CompanyModel.getInstance();
DepartmentManager manager = model.getDataObjectManager(CompanyModel.department);
treeController.setDataObjects(
new TreeDataObjects(
new ManagerDataObjects(manager),
new ChildRelation(CompanyModel.department,Department.employees)));
// building a context menu for the tree
ContextMenu menu = new ContextMenu();
menu.add(new OpenInEditorAction(treeController));
menu.add(new OpenInEditorPerspectiveAction(treeController));
menu.add(new OpenNewDepartmentWizardAction(treeController));
menu.add(new OpenNewEmployeeWizardAction(treeController));
menu.add(new ChangeEmployeeDepartmentAction(treeController));
menu.add(new ShowDepartmentEmployeesAction(treeController));
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
menu.add(new RemoveDataObjectAction(treeController));
treeController.setContextMenu(this.getSite(),menu);
}
@Override
public void setFocus() {
this.treeController.getViewer().getControl().setFocus();
}
}
Let’s register the corresponding extension (org.eclipse.ui.views)

the result:
Employees table
/**
* Creates a view that contains
* a table displaying information about Employees
*/
public class EmployeesView extends ViewPart{
private TableViewerController tableController = null;
/**
* Opens the view and passes to the controller
* a collectionof<code>Employee</code>s to be represented
* in a table within the view.
*/
public static void setEmployees(List<? extends Employee> employess){
EmployeesView view = getView();
view.tableController.setDataObjects( new CollectionDataObjects(employess));
}
/**
* Opens the view and passes to the controller
* a collection of <code>Employee</code>s to be represented
* in a table within the view.
* The collectionof <code>Employee</code>s is specified via
* the association with the<code>Department</code> object (Department.employees)
*/
public static void setDepartment(Department department){
EmployeesView view = getView();
IDataField<Set<Employee>> field = department.getDataField(Department.employees);
view.tableController.setDataObjects(new RelationDataObjects(field));
}
@Override
public void createPartControl(Composite parent) {
// Creating a controller
tableController = new TableViewerController(parent);
// Setting layout
GridData data = new GridData(GridData.FILL,GridData.FILL,true,true);
tableController.getViewer().getControl().setLayoutData(data);
// Specifying data presentation.
// Passing to the controller an OddBackgroundColorPresentation instance
// that pastes the background of even table cells
// with the color specified. Default is RGB(230,230,255)
tableController.setDataPresenation(
new EvenBackgroundColorPresentation(tableController));
// Configuring table columns.
// Using ColumnData to wrap up data object fields to be represented in tree nodes.
// (Data object fields are indicatedthrough<code>FieldDeclaration</code>s)
tableController.setColumnProvider(
new ColumnProvider(
new ColumnData(CompanyModel.employee,Employee.firstName),
new ColumnData(CompanyModel.employee,Employee.lastName),
new ColumnData(CompanyModel.employee,Employee.phoneNumber),
new ColumnData(CompanyModel.employee,Employee.salary)));
// Adding actions that open a dialog for column selection
ChangeColumnsAction.registerInMenu(this, tableController);
ChangeColumnsAction.registerInToolBar(this, tableController);
// adding a context menu
ContextMenu menu = new ContextMenu();
menu.add(new OpenInEditorAction(tableController));
menu.add(new OpenInEditorPerspectiveAction(tableController));
menu.add(new ChangeEmployeeDepartmentAction(tableController));
menu.add(new RemoveDataObjectAction(tableController));
tableController.setContextMenu(this.getSite(),menu);
}
@Override
public void setFocus() {
this.tableController.getViewer().getControl().setFocus();
}
/**
* Opens EmployeesView
*/
private static EmployeesView getView(){
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
EmployeesView result = null;
try {
for (IViewReference ref : page.getViewReferences()) {
if ("example.model.eclipse.views.EmployeesView".equals(ref.getId())) {
result = (EmployeesView) ref.getView(true);
break;
}
}
if (result == null)
result = (EmployeesView) page.showView("example.model.eclipse.views.EmployeesView");
} catch (PartInitException e) {
throw new RuntimeException(e);
}
return result;
}
}
Let’s add an extension

the result:
Employee search panel
Let’s create a panel. The panel will give an
ability to search Employees by input parameters and show them in the table.
public class SearchEmployeeView extends ViewPart implements IWidgetsContext{
private Label firstNameLabel;
private Text firstName;
private Label secondNameLabel;
private Text secondName;
private Label DepartmentLabel;
private DialogChooser<Department> department;
private Button searchButton;
private ContextControllerBinder contextBinder;
private SelectionAdapter doSearch = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
CompanyModel model = CompanyModel.getInstance();
EmployeeManager manager = model.getDataObjectManager(CompanyModel.employee);
String first = firstName.getText();
String second = secondName.getText();
Department d = department.getObject();
List<Employee> list = (d == null) ?
manager.findEmployee(first,second) : manager.findEmployee(first, second, d);
EmployeesView.setEmployees(list);
}
};
@Override
public void createPartControl(Composite parent) {
parent.setLayout(new GridLayout(2,false));
ContextControllerBinder binder = getContextBinder();
firstNameLabel = new Label(parent, SWT.NULL);
firstNameLabel.setLayoutData(new GridData());
binder.bind(firstNameLabel,CompanyModel.employee,Employee.firstName);
firstName = new Text(parent, SWT.BORDER | SWT.SINGLE);
firstName.setLayoutData(new GridData(GridData.FILL,GridData.FILL,true,false));
secondNameLabel = new Label(parent, SWT.NULL);
secondNameLabel.setLayoutData(new GridData());
binder.bind(secondNameLabel,CompanyModel.employee,Employee.lastName);
secondName = new Text(parent, SWT.BORDER | SWT.SINGLE);
secondName.setLayoutData(new GridData(GridData.FILL,GridData.FILL,true,false));
departmentLabel = new Label(parent, SWT.NULL);
departmentLabel.setLayoutData(new GridData());
binder.bind(departmentLabel,CompanyModel.department);
department = newDialogChooser<Department>(parent);
department.setLayoutData(new GridData(GridData.FILL,GridData.FILL,true,false));
CompanyModel model = CompanyModel.getInstance();
binder.bind(department,model.getDataObjectManager(CompanyModel.department));
searchButton = new Button(parent,SWT.PUSH);
searchButton.setText("Search");
ImageDescriptor id = AbstractUIPlugin.imageDescriptorFromPlugin(
"example.org.fishbolt.model.eclipse","icons/search.gif");
searchButton.setImage(id.createImage());
searchButton.setLayoutData(new GridData(GridData.END,GridData.FILL,false,false,2,1));
searchButton.addSelectionListener(doSearch);
}
@Override
public void setFocus() {
this.firstName.setFocus();
}
public void contextWidgetChanged(EditableWidgetController<Widget, Object, Object> controller,
PresentationException exception) {
}
public ContextControllerBinder getContextBinder() {
return (contextBinder == null) ?
contextBinder = new ContextControllerBinder(this) : contextBinder ;
}
}
Let’s add an extension
Application UI
As a result we got a an Eclipse based application. The application allows to create view edit and delete the database data. The UI is user friendly and responsive – changing a data object in editor or deleting it a view automaticaly causes a refresing the corresponding data in other views.
It’s easy to change or extend the data due to the data structure errors evaluation at the compilation stage. It’s because the UI dependency mostly presented by data object’s java constants references.
Additional resources
The additional information about abilities of the Eclipse UI for the data model see at
the
User interface for the data model in Eclipse IDE. See also libraries: