Blog

JavaOne 2014 - Visualize your DSL - Building 3d Lego models with Xtext and JavaFX

JavaOne 2014 is not too far ahead and because I'm doing 2 session:

I've been busy working on show cases and the demo application. The demo application visualizes 3d objects of any kind, I thought a nice and not too complex example are structures built from lego bricks. Naturally one can create Lego 3d models using any 3d modeling software but for someone like me who is not using them on a daily base this is a bit cumbersome and I'm faster using a DSL who allows me to those in a textual editor inside my IDE and so I defined a DSL who allows me to define lego bricks and mix and match them to create bigger structures. Definition Lego DuploTm Bricks: lego_bricks Definition of a Lego DuploTm structure: lego_assembly The reality: Foto The really interesting thing in this regard is that to create a visual representation of the editor content (the editors are on the left hand side of the Eclipse IDE screenshots) is that all that needs to be done is to contribute an adapter into your IDE which adapts your editor (must not be xtext based) and provide an FXML representation of the editors content. For the above editors this looks like this: The adapter for the xtext-editor:

package at.bestsolution.lego.ui.preview;

import java.net.URL;
import java.util.Collections;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.fx.ide.ui.editor.IFXMLProviderAdapter;
import org.eclipse.ui.IEditorPart;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.XtextEditor;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;

import at.bestsolution.lego.lego.Model;
import at.bestsolution.lego.ui.internal.LegoActivator;

import com.google.inject.Injector;

public class FXMLProviderAdapter implements IFXMLProviderAdapter {
	private XtextEditor editor;
	
	public FXMLProviderAdapter(XtextEditor editor) {
		this.editor = editor;
	}

	@Override
	public IEditorPart getEditorPart() {
		return editor;
	}
	
	@Override
	public String getPreviewFXML() {
		return editor.getDocument().readOnly(new IUnitOfWork<String, XtextResource>() {

			@Override
			public String exec(XtextResource resource) throws Exception {
				Injector injector = LegoActivator.getInstance().getInjector("at.bestsolution.lego.Lego");
				PreviewGenerator generator = injector.getInstance(PreviewGenerator.class);
				return generator.generatePreview((Model) resource.getContents().get(0)).toString();
			}
			 
		});
	}
		
	@Override
	public String getPreviewSceneFXML() {
		return null;
	}

	@Override
	public List<String> getPreviewCSSFiles() {
		return Collections.emptyList();
	}

	@Override
	public String getPreviewResourceBundle() {
		return null;
	}

	@Override
	public List<URL> getPreviewClasspath() {
		return Collections.emptyList();
	}

	@Override
	public IFile getFile() {
		return editor.getDocument().readOnly(new IUnitOfWork<IFile, XtextResource>() {

			@Override
			public IFile exec(XtextResource resource) throws Exception {
				URI uri = resource.getURI();
				Path structureFilePath = new Path(uri.toPlatformString(true));
				IFile f = ResourcesPlugin.getWorkspace().getRoot().getFile(structureFilePath);
				if( f.exists() ) {
					return f;
				}
				return null;
			}
			
		});
	}
}

The adapter factory registered inside the Eclipse IDE:

package at.bestsolution.lego.ui.preview;

import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.fx.ide.ui.editor.IFXMLProviderAdapter;
import org.eclipse.fx.ide.ui.editor.IFXPreviewAdapter;
import org.eclipse.xtext.ui.editor.XtextEditor;

public class FXMLAdapterFactory implements IAdapterFactory {

	@Override
	public Object getAdapter(Object adaptableObject, Class adapterType) {
		if((adapterType == IFXMLProviderAdapter.class || adapterType == IFXPreviewAdapter.class) && adaptableObject instanceof XtextEditor ) {
			XtextEditor editor = (XtextEditor) adaptableObject;
			if( "at.bestsolution.lego.Lego".equals(editor.getLanguageName()) ) {
				return new FXMLProviderAdapter(editor);
			}
		}
		return null;
	}

	@Override
	public Class[] getAdapterList() {
		return new Class[]{IFXMLProviderAdapter.class, IFXPreviewAdapter.class};
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
  <!-- .... -->
  <extension
        point="org.eclipse.core.runtime.adapters">
     <factory
            adaptableType="org.eclipse.xtext.ui.editor.XtextEditor"
            class="at.bestsolution.lego.ui.preview.FXMLAdapterFactory">
         <adapter
               type="org.eclipse.fx.ide.ui.editor.IFXPreviewAdapter">
         </adapter>
         <adapter
               type="org.eclipse.fx.ide.ui.editor.IFXMLProviderAdapter">
         </adapter>
      </factory>
  </extension>
  <!-- .... -->
</plugin>
published on
Previous
JavaOne 2014 - Having fun with Lego & JavaFX 3d