We had to build an Eclipse RCP application where SQL statements could be edited. At first, we used a StyledText widget to do this. Soon, we were in need of extra features like syntax coloring, content assist etc. Why not use a ‘ready to use’ SQLEditor to open a SQL file you say? Well, we wanted to ’embed’ the area in our own editor. The SQL area should be part of the editor and not the only thing in the editor!

After a while we discovered a normal StyledText was not the way to do this. After some investigation we found a widget which fits our needs perfectly.. The SQLStatementArea widget which is part of the Eclipse Data Tools Platform (DTP). After installing all necessary plugins, coding could begin..

The SQLStatementArea widget can be used like any other widget in a Editor.

ISQLSourceViewerService viewerService = new CustomSQLSourceViewerService();
SQLStatementArea sta = new SQLStatementArea(this, SWT.BORDER, viewerService, true);
sta.setEditable(true);
sta.setEnabled(true);
  • this: the SWT Composite where the area should be in
  • SWT.BORDER: we want a border to be visible, other styles can be added as usual
  • viewerService: an instance of a class implementing ISQLSourceViewerService (talk about this in a minute)
  • true: when this is true, line numbers are visible

When instantiating the SQLStatementArea a class implementing ISQLSourceViewerService is needed as mentioned earlier. In this class a help method needs to be implemented which will define the PartitionScanner for the document. This method determines where the text has to be scanned for.

This is the code of the method we used for this class:

@Override
public void setUpDocument(IDocument doc, String dbType) {
SQLPartitionScanner sqlPartitionSanner = new SQLPartitionScanner();
if(doc instanceof IDocumentExtension3)
{
IDocumentExtension3 extension3 = (IDocumentExtension3) doc;
FastPartitioner _partitioner = new FastPartitioner(sqlPartitionSanner, new String[]
{
SQLPartitionScanner.SQL_CODE,
SQLPartitionScanner.SQL_COMMENT,
SQLPartitionScanner.SQL_MULTILINE_COMMENT,
SQLPartitionScanner.SQL_STRING,
SQLPartitionScanner.SQL_DOUBLE_QUOTES_IDENTIFIER
});
_partitioner.connect(doc);
extension3.setDocumentPartitioner(ISQLPartitions.SQL_PARTITIONING,     _partitioner);
}
}

Next in line is the SourceViewerConfiguration. This class is responsible for syntax coloring, content assist etc. In our application we’ve used the code from here, because it is more advanced and extensive (multi-line comments for example). However , the code in the available plugins is sufficient for this tutorial. The configuration class to use for a SQL configuration is the SQLSourceViewerConfiguration which can be found in the org.eclipse.datatools.sqltools.sqlbuilder.views.source package.

SQLSourceViewerConfiguration sqlSourceViewerConfiguration = new SQLSourceViewerConfiguration();
sta.configureViewer(sqlSourceViewerConfiguration);

There are still a few things that need to be added in order for the SQLStatementArea to work. As most widgets, it needs a layoutdata, but it also needs a document which holds the actual input. Because were going to add databinding later, we’re setting up an empty document for now.

sta.setLayoutData(new GridData(GridData.FILL_BOTH));
document = new Document();
document.set("");
sta.getViewer().setDocument(document);

Our next step is to add databinding so the text is displayed correctly and the object is updated immediately  This is easy because the SQLStatementArea holds a StyledText widget which we can use to create the binding. When you’re not familiar with databinding you can check out this great tutorial or just set the text of the document for now (instead of empty).

IObservableValue observeTextObserveWidget = SWTObservables.observeText(sta.getViewer().getTextWidget(), SWT.Modify);
IObservableValue sqlSql_statementObserveValue = EMFEditProperties.value(editingDomain, Literals.DOCUMENT_SQL_STATEMENT__SQL_STATEMENT).observe(sql);
bindingContext.bindValue(styledTextStatementObserveTextObserveWidget, sqlSql_statementObserveValue, null, null);
  • editingDomain: we’re connecting the binding to our editingdomain for undo/redo functionality and dirty state (use EMFProperties when not using an editingdomain)
  • sql: the EMF object which holds our SQL statement

When running the application, the result is an editor which holds a great area for editing SQL.

SQLStatementArea integrated in Eclipse Editor

SQLStatementArea integrated in Eclipse Editor

The only thing is, when hitting CTRL+SPACE now, content assist doesn’t work. This is because we have to ‘bind’ the content assist of our SQLStatementArea with the Eclipse content assist.

handlerService = (IHandlerService) editor.getSite().getService(IHandlerService.class);
IHandler cahandler = new AbstractHandler() {
public Object execute(ExecutionEvent event) throws ExecutionException {
sta.getViewer().doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
return null;
}
};
if(contentAssistHandlerActivation != null){
handlerService.deactivateHandler(contentAssistHandlerActivation);
}
contentAssistHandlerActivation = handlerService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS,
cahandler);

Now, when starting the application again, content assist will work!

SQLStatementArea integrated in Eclipse Editor with content assist

SQLStatementArea integrated in Eclipse Editor with content assist

When using this in an application we recommend to use the code mentioned earlier or to write your own. This way you can have far more keywords, multi-line comments, content formatting (uppercase/lowercase) and so on. But we hope this tutorial gives you a great start!

Goal:

For an RCP application which we are building at the moment we were in need of a Tree with checkboxes. It ‘s not just a question of using the JFace CheckboxTreeViewer because we wanted to control on which level in the tree the checkbox was shown. As you know, the CheckboxTreeViewer shows a checkbox on every level.

An added bonus is that now, we can change the look of the checkbox by supplying our own images.

After some investigation, I found this solution to be the easiest:

Solution:

1.
The first thing you need are two custom icons, one for a checked and one for an unchecked checkbox. I’ve used these icons for this example:

 

2.
Create a JFace TreeViewer with one TreeViewerColumn and three TreeItems (don’t use TreeItems with a TreeViewer in your application, use ContentProvider and LabelProvider instead). Add the unchecked icon to the TreeItems on the second level.

Example:

Composite compositeExample = new Composite(composite, SWT.NONE);
compositeExample.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
TreeColumnLayout tcl_compositeExample = new TreeColumnLayout();
compositeExample.setLayout(tcl_compositeExample);

TreeViewer treeViewerExample = new TreeViewer(compositeExample, SWT.BORDER | SWT.FULL_SELECTION);
treeExample = treeViewerExample.getTree();
treeExample.setHeaderVisible(true);
treeExample.setLinesVisible(true);

TreeViewerColumn treeViewerColumnName = new TreeViewerColumn(treeViewerExample, SWT.NONE);
TreeColumn trclmnName = treeViewerColumnName.getColumn();
tcl_compositeExample.setColumnData(trclmnName, new ColumnWeightData(100, ColumnWeightData.MINIMUM_WIDTH, true));
trclmnName.setText("Name");

TreeItem trtmParent = new TreeItem(treeExample, SWT.NONE);
trtmParent.setImage(ResourceManager.getPluginImage("your_plugin_name", "your_image_name"));
trtmParent.setFont(FontConstants.FONT_NORMAL);
trtmParent.setText("Parent");

TreeItem trtmChild = new TreeItem(trtmParent, SWT.NONE);
trtmChild.setFont(FontConstants.FONT_NORMAL);
trtmChild.setImage(imgUnChecked);
trtmChild.setText("Child");

TreeItem trtmChild_1 = new TreeItem(trtmParent, SWT.NONE);
trtmChild_1.setFont(FontConstants.FONT_NORMAL);
trtmChild_1.setImage(imgUnChecked);
trtmChild_1.setText("Child");
trtmParent.setExpanded(true);

Once you have filled your tree and have a screen similar to below, you can add the real functionality.

3.
Now the icon has to change when the user clicks on it. We can achieve this by adding the following MouseListener to the tree. It will listen to clicks inside the tree and compare it with the items inside the tree. Once you know the clicked item, you can change his image.

tree_1.addMouseListener(new MouseListener(){

	@Override
	public void mouseDoubleClick(MouseEvent e) {
	}

	@Override
	public void mouseDown(MouseEvent e) {
		for(TreeItem item : tree_1.getSelection()) {
			if(item.getImage() != null) {
				if((e.x > item.getImageBounds(0).x) && (e.x < (item.getImageBounds(0).x + item.getImage().getBounds().width))) {
					if((e.y > item.getImageBounds(0).y) && (e.y < (item.getImageBounds(0).y + item.getImage().getBounds().height))) {
						setChecked(item);
					}
				}
			}
		}
	}

	@Override
	public void mouseUp(MouseEvent e) {
}});

private void setChecked(TreeItem item) {
	if(item.getImage().equals(imgUnChecked)) {
		item.setImage(imgChecked);
	}
	else {
		item.setImage(imgUnChecked);
	}
}

4.
Run you program and click on the icons, you will see that they really act like a checkbox. Now all you have to do is customize it!