Associate and Open Files

An Eclipse based product is a stand-alone program built with the Eclipse platform. In many cases such a program would like to be associated with particular file types or extensions. For example, the Eclipse IDE could be configured to open all Java files. This would allow a user to double click on a Java file and have it be opened in a running Eclipse IDE instance or start a new instance of the Eclipse IDE if it was not previously running. In order to support this coordination is needed between the Eclipse native launcher, SWT, the workbench and the RCP application.

New command line options have been added to support this scenario:

The openFile argument opens the specified file in an instance of Eclipse. If an instance is not already running then a new instance will be started.

  eclipse --launcher.openFile myFile.txt

A second option is needed to configure the launcher to automatically perform the open file request without requiring the user to always specify --launcher.openFile. A new "default action" argument has been introduced to accomplish this. This option can go in the launcher.ini (eclipse.ini) file, the value must be "openFile":

  ...
  -showsplash
  org.eclipse.platform
  --launcher.defaultAction
  openFile
  -vmargs
  -Xms256m
  -Xmx768m

This tells the launcher that if none of the command line arguments start with "-" then all command line arguments should be treated as if they followed the "--launcher.openFile" argument.

  eclipse myFile.txt

This option was added because without registry changes, this is the kind of command line the launcher will receive on windows when you double click a file that is associated with eclipse, or you select files and choose "Open With" or "Send To" Eclipse.

Talking to SWT

The launcher talks to SWT through the use of a hidden window. The launcher and SWT both need to agree on the name of this window. This allows the launcher to find an already running eclipse and tell it to open the file. Any RCP application will need to ensure they get this right for things to work.

The launcher bases this on its "official name". The official name can be set with the -name argument. If -name is not set, then the official name is derived from the launcher executable, the extension is removed and the first letter is capitalized: rcp.exe becomes Rcp.

SWT bases this on the value set with the Display.setAppName() function. Normally, this is set by the Workbench when it creates the display and the value is the "appName" taken from the product extension point.

Listening to SWT.OpenDocument Events

The launcher communicates with SWT to inform SWT about a request to open one or more files. SWT then can fire the SWT.OpenDocument event. For an RCP application to take advantage of this it must register a listener for the SWT.OpenDocument event. It should register this listener before calling PlatformUI.createAndRunWorkbench so that the listener is in place before the workbench starts running the event loop.

The event loop will start running while the splash screen is still up, so events may arrive before the workbench is ready to actually open an editor for the file. This means that the listener should save the file paths it gets from the OpenDocument events so they can be opened at some later time. WorkbenchAdvisor.eventLoopIdle can be a good place to check for saved open file events.

Here is an example RCP application that does this. First is the IApplication implementation:

public class Application implements IApplication {	

	public Object start(IApplicationContext context) {
		OpenDocumentEventProcessor openDocProcessor = 
			new OpenDocumentEventProcessor();

		Display display = PlatformUI.createDisplay();
		display.addListener(SWT.OpenDocument, openDocProcessor);

		try {
			int returnCode = PlatformUI.createAndRunWorkbench(display, new 
				ApplicationWorkbenchAdvisor(openDocProcessor));
			if (returnCode == PlatformUI.RETURN_RESTART) {
				return IApplication.EXIT_RESTART;
			}
			return IApplication.EXIT_OK;
		} finally {
			display.dispose();
		}
	}
	...
}

Next is an example SWT Listener that listens to the SWT.OpenDocument event:

public class OpenDocumentEventProcessor implements Listener {
	private ArrayList<String> filesToOpen = new ArrayList<String>(1);
	
	public void handleEvent(Event event) {
		if (event.text != null)
			filesToOpen.add(event.text);
	}

	public void openFiles() {
		if (filesToOpen.isEmpty())
			return;

		String[] filePaths = filesToOpen.toArray(
			new String[filesToOpen.size()]);
		filesToOpen.clear();
		
		for (String path : filePaths) {
			// open the file path
		}
	}
}

Finally we need a WorkbenchAdvisor that will open the files durying eventLoopIdle:

public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
	private OpenDocumentEventProcessor openDocProcessor;

	public ApplicationWorkbenchAdvisor(
			OpenDocumentEventProcessor openDocProcessor) {
		this.openDocProcessor = openDocProcessor;
	}

	...

	public void eventLoopIdle(Display display) {
		openDocProcessor.openFiles();
		super.eventLoopIdle(display);
	}
}