Frank's Eclipse and Java Blog

Sunday, February 13, 2005

Workspace-aware file dialog?

In my recent effort to create a search for unused property names, I had the need for a file dialog allowing a user to specify a properties file. However, I wanted the dialog to restrict its view to the workspace and to my surprise I could not find a built-in dialog that does that! The SWT FileDialog offers up the entire filesystem and knows nothing about the Eclipse workspace, and the ResourceSelectionDialog - which is workspace aware - shows two panes and checkboxes and does not look at all like the usual open file dialog...

I was looking for something that looks like the resource perspective's navigator view, but as a modal selection dialog. I could have sworn that I'd seen that used elsewhere in Eclipse, but I could not find it, and I had others ask me the same question, so I decided to look at how to do just that: embed (parts of) the Eclipse Navigator view in a file selection dialog, and it turned out to be relatively simple!

The key to doing this is the org.eclipse.ui.model.WorkbenchContentProvider, which turns out to be the real workhorse behind the navigator view. It provides all the knowledge about the workspace resources. With this content provider and the WorkbenchLabelProvider from the same package, writing this workspace aware file selection dialog was a snap!

Here's how to create a Dialog with an embedded resource navigator (not the complete code, which is here):

public class WSFileDialog extends Dialog {

private TreeViewer viewer;

protected Control createDialogArea(Composite parent) {
Composite comp = (Composite) super.createDialogArea(parent);
getShell().setText(title);
TreeViewer viewer = createViewer(comp);
GridData data = new GridData(GridData.FILL_BOTH);
...
viewer.getControl().setLayoutData(data);
return comp;
}

protected TreeViewer createViewer(Composite parent) {
ResourceNavigator nav = new ResourceNavigator();
viewer = new TreeViewer(parent, selectionStyle |
SWT.H_SCROLL |
SWT.V_SCROLL |
SWT.BORDER);
viewer.setUseHashlookup(true);
initContentProvider(viewer);
initLabelProvider(viewer);
initFilters(viewer);
viewer.setInput(rootElement);
if (expand) {
viewer.expandToLevel(2);
}
return viewer;
}

protected void initContentProvider(TreeViewer viewer) {
viewer.setContentProvider(new WorkbenchContentProvider());
}

protected void initLabelProvider(TreeViewer viewer) {
viewer.setLabelProvider(
new DecoratingLabelProvider(
new WorkbenchLabelProvider(),
IDEWorkbenchPlugin.getDefault().getWorkbench()
.getDecoratorManager().getLabelDecorator()));
}
...

}

There are some additional bells and whistles, but that's basically it! The only other interesting part is the initFilters method, because this is where the built-in filters actually can not be used. The navigator filters remove the positive matches of the filter, whereas I wanted to only show files with a certain extension, and directories regardless. The following filter does the trick:

private class FilePatternFilter extends ViewerFilter {

public boolean select(Viewer viewer,
Object parentElement,
Object element) {
if (extensions == null || extensions.length == 0)
return true;
IResource resource = null;
if (element instanceof IResource) {
resource = (IResource) element;
} else if (element instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
resource = (IResource) adaptable
.getAdapter(IResource.class);
}
if (resource != null && !resource.isDerived()) {
if (resource.getType() != IResource.FILE) return true;
String extension = resource.getFileExtension();
if (extension == null) return true;
for (int i = 0; i < extensions.length;i++) {
if (extension.equalsIgnoreCase(extensions[i]))
return true;
}
}
return false;
}
}

If you are still reading this, you're probably interested in the entire code. The code is available from the CVS repository for my metrics plugin (Didn't feel like creating an entire new sourceforge project for this). Create a repository entry for cvs.sourceforge.net, root folder /cvsroot/metrics, check out the biz.volantec.utils project. The fully qualified name of the file dialog is biz.volantec.utils.widgets.WSFileDialog

Please note that I'm doing this work on Eclipse 3.1M4 (on a Mac OSX 10.3.8) and I already know that some of this (the SearchJob) does not work on 3.0.1 or older. I need to find a public API to do the text searches, but I'm not there yet. The (unfortunately internal) API of the TextSearchEngine has changed between 3.0.1 and 3.1