Xtext & JavaFX Tom Schindl <[email protected]> Twitter: @tomsontom Blog: http://tomsondev.bestsolution.at Website: http://www.bestsolution.at
Xtext & JavaFX
Tom Schindl <[email protected]>
Twitter: @tomsontomBlog: http://tomsondev.bestsolution.atWebsite: http://www.bestsolution.at
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
About Me‣ CTO BestSolution.at Systemhaus GmbH
‣ Eclipse Committer
‣ e4
‣ Platform
‣ EMF
‣ Project lead
‣ e(fx)clipse
‣ Twitter: @tomsontom
‣ Blog: tomsondev.bestsolution.at
‣ Cooperate: http://bestsolution.at
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
What is JavaFX‣ JavaFX is a scenegraph based graphics toolkit
‣ Provides
‣ 2d graphic primitives like Rectangle, Circle, Path, …
‣ Controls built on top of it like TextField, TableView, …
‣ 3d graphic primitives like a Mesh, Cube, …
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
What is JavaFX‣ JavaFX comes with FULL CSS support
‣ All properties of scenegraph elements can be styled with CSS
‣ Support for CSS2 selectors (CSS3 is only supported partially)
‣ Has a Java API so it can be targeted by ANY jvm-language (Java, Groovy, Xtend, JavaScript, …)
‣ Has an OPTIONAL declarative way to define UIs named FXML
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Elementary
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Demo JavaFX apps
‣Elementary
‣ e4 + JavaFX application
‣ highlights 3d support
‣ 3d model defined with a Xtext-DSL
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Business App
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Demo JavaFX apps
‣BiSCAT
‣ e4 + JavaFX + SWT on JavaFX application
‣ Formbased business UI
‣ Highlights direct reuse of old SWT-Code in a JavaFX environment
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX and Text‣ javafx.scene.text.Text
‣ allows to define font-size, font-name, … & fill color
‣ can display multiple lines
‣ can not have multiple colors, font-size, …
Text t = new Text("I'm a text with font-size 20");t.setFont(Font.font(20));
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ javafx.scene.text.TextFlow:
‣ allows to layout multiple text nodes
‣ is able to display multiple nodes different font- size, fill color, …
‣ renderes ALL text nodes no matter if visible or not in the viewport
‣ has no notion of editing, …
FX and Text
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
TextFlow f = new TextFlow();
Text t1 = new Text("I'm black 12pt");t1.setFont(Font.font(12));f.getChildren().add(t1);
Text t2 = new Text("I'm red 20pt");t2.setFont(Font.font(20));t2.setFill(Color.RED);f.getChildren().add(t2);
FX and Text
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ javafx.scene.control.Label
‣ Allows to display multiple lines of text including e.g. an icon on the left
‣ Allows only one font-size, … & fill color
‣ Has no support for editing
FX and Text
Label l = new Label("I'm a Label with 20pt");l.setFont(Font.font(20));
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ javafx.scene.control.TextField
‣ Single line editable of text
‣ Allows only one font-size, … & fill color
FX and Text
TextField f = new TextField("I'm a text field");
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ javafx.scene.control.TextArea
‣ Multiple lines of text
‣ Allows only one font-size, … & fill color
‣ Renderers ALL text in one big Text-Node!
FX and Text
TextArea t = new TextArea();StringBuilder b = new StringBuilder();b.append("This is a multiline text\n");b.append("This is a multiline text\n");b.append("This is a multiline text\n");t.setText(b.toString());
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx text controls‣ o.e.f.ui.controls.styledtext.StyledString
‣ implements CharSequence (many e(fx)clipse APIs allow CharSequence in their API e.g. TreeCells)
‣ made up of multiple segments where each segment has a list of CSS-Classes attached
‣ …Util.toNode(StyledString) : Node allows to convert a StyledString to a scenegraph Node
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
BorderPane p = new BorderPane();
StyledString ss = new StyledString();ss.appendSegment("Styled", "h1");ss.appendSegment("String", "h1","colorful");
p.setCenter(Util.toNode(ss));
Scene s = new Scene(p);s.getStylesheets().add(getClass().getResource("styled-string.css").toExternalForm());
FX & efx text controls
.h1 {-fx-font-size: 20pt;
}
.colorful {-fx-font-weight: bold;-fx-fill: linear-gradient( from 0.0% 0.0% to 100.0% 100.0%, rgb(128,179,128) 0.0,
rgb(255,179,102) 100.0);}
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ o.e.f.ui.controls.styledtext.StyledLabel
‣ Similar API as javafx.scene.control.Label
‣ uses a StyledString instead of a String
FX & efx text controls
BorderPane p = new BorderPane();
StyledString ss = new StyledString();ss.appendSegment("Styled", "h1");ss.appendSegment("Label", "h1","colorful");
StyledLabel l = new StyledLabel(ss);p.setCenter(l);
Scene s = new Scene(p);s.getStylesheets().add(getClass().getResource("styled-string.css").toExternalForm());
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ o.e.f.ui.controls.styledtext.StyledTextArea
‣ Allows to edit multiple lines of text
‣ Allows to display different colors, fonts, …
‣ VIRTUAL rendering - only text visible in the view port is rendered
‣ Content is kept in StyledTextContent class
FX & efx text controls
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
BorderPane p = new BorderPane();
StyledTextArea a = new StyledTextArea();a.getContent().setText("public class Sample {\n\n}");a.setStyleRanges(new StyleRange("keyword", 0, "public".length(), null, null),new StyleRange("keyword", "public".length()+1, "class".length(), null, null)
);a.setLineRulerVisible(true);p.setCenter(a);
Scene s = new Scene(p);s.getStylesheets().add(getClass().getResource("styled-text.css").toExternalForm());
.keyword {-styled-text-color: rgb(127, 0, 85);-fx-font-weight: bold;
}
FX & efx text controls
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX, efx & Eclipse Text‣ org.eclipse.text is UI neutral Code/Text Framework
‣ Provides document abstraction
‣ Provides tokenizing
‣ org.eclipse.jface.text
‣ Built on top of org.eclipse.text
‣ Uses SWT to visualize information provided by o.e.text
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ org.eclipse.fx.text & org.eclipse.fx.text.ui
‣ JavaFX port of org.eclipse.jface.text
‣ Works with StyledTextArea
‣ Special StyledTextContent implementation backed by IDocument
‣ Provides SourceViewer class to implement code editors
FX, efx & Eclipse Text
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
__state_comment
FX, efx & Eclipse Text‣ Step 1 Partitioning
__dftl_partitioning
/* * This is a multiline comment */
input signal INPUT_SIGoutput signal OUTPUT_SIG
state START
set INPUT_SIG = true
end
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX, efx & Eclipse Text‣ Step 1 Partitioning
Document document = new Document();
FastPartitioner partitioner = new FastPartitioner(new StatemachinePartitionScanner(), "__state_comment");
document.setDocumentPartitioner("__dftl_paritioning", partitioner);partitioner.connect(document);
public class StatemachinePartitionScanner extends RuleBasedPartitionScanner {public StatemachinePartitionScanner() {
IPredicateRule[] pr = new IPredicateRule[1];pr[0] = new MultiLineRule("/*", "*/",
new Token("__state_comment"), (char)0, false);
setPredicateRules(pr);}
}
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX, efx & Eclipse Text‣ Step 2 Tokenizing
/* * This is a multiline comment */
input signal INPUT_SIGoutput signal OUTPUT_SIG
state START
set INPUT_SIG = true
end
tk(“state_doc_default“,0,37)
tk(“state_keyword“,38,43)
tk(“state_keyword“,44,48)
tk(“state_default“,49,58)
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ Step 2 Tokenizing
FX, efx & Eclipse Text
public class StatemachineSourceConfiguration extends SourceViewerConfiguration {@Overridepublic IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {PresentationReconciler reconciler = new PresentationReconciler();
{DefaultDamagerRepairer dr = new DefaultDamagerRepairer( new StatemachineCodeScanner());reconciler.setDamager(dr, "__dftl_paritioning");reconciler.setRepairer(dr, "__dftl_paritioning");
}{DefaultDamagerRepairer dr = new DefaultDamagerRepairer( new StatemachineDocScanner());reconciler.setDamager(dr, "__state_comment");reconciler.setRepairer(dr, "__state_comment");
}
return reconciler;}
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX, efx & Eclipse Text
public class StatemachineCodeScanner extends RuleBasedScanner {public StatemachineCodeScanner() {
Token keywordToken = new Token(new TextAttribute("state_keyword"));Token defaultToken = new Token(new TextAttribute("state_default"));setDefaultReturnToken(defaultToken);
IRule[] rules = new IRule[1];
JavaLikeWordDetector wordDetector= new JavaLikeWordDetector();CombinedWordRule combinedWordRule= new CombinedWordRule(wordDetector, defaultToken);
CombinedWordRule.WordMatcher wordRule= new CombinedWordRule.WordMatcher();wordRule.addWord("signal", keywordToken);// …wordRule.addWord("false", keywordToken);combinedWordRule.addWordMatcher(wordRule);rules[0] = combinedWordRule;setRules(rules);
}}
‣ Step 2 Tokenizing
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ Step 3 SourceViewer configuration
FX, efx & Eclipse Text
Document document = new Document();SourceViewer viewer = new SourceViewer();StatemachineSourceConfiguration configuration = new StatemachineSourceConfiguration( document, new File("/tmp/StateSample.state"));
// … setup paritioning
viewer.configure(configuration);viewer.setDocument(document);
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ Step 4 Define colors through CSS
.state.styled-text-area .state_default {-styled-text-color: rgb(0,0,0);
}
.state.styled-text-area .state_keyword {-styled-text-color: rgb(127, 0, 85);-fx-font-weight: bold;
}
.state.styled-text-area .state_doc_default {-styled-text-color: rgb(63, 127, 95);
}
public class StatemachineSourceConfiguration extends SourceViewerConfiguration {@Overridepublic String getStyleclassName() {
return "state";}
}
FX, efx & Eclipse Text
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx & Xtext
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx & Xtext‣ Make use of the NEW „Generic IDE support“ who generates 2 projects who don’t require OSGi nor Eclipse Framework
‣ ….$language: core parsing infrastructure
‣ ….$language.ide: ide specific infrastructure including a special parser & lexer
‣ ….$language.fx (Handcrafted): FX-Text support like SourceViewerConfiguration, Partitioner, …
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx & Xtext
class StatemachineFXModule extends AbstractGenericModule {
val ExecutorService executorService
def configureExecutorService(Binder binder) {binder.bind(ExecutorService).toInstance(executorService)
}
def configureContentAssistLexer(Binder binder) {binder.bind(Lexer).annotatedWith(Names.named(LexerIdeBindings.CONTENT_ASSIST)).to(InternalStatemachineLexer)
}
def Class<? extends IContentAssistParser> bindIContentAssistParser() {StatemachineParser
}}
‣ Step 1: Setup Guice module for editing
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx & Xtext‣ Step 2: Create Guice Injector
injector = new StatemachineStandaloneSetup() {
public Injector createInjector() {StatemachineRuntimeModule runtimeModule = new StatemachineRuntimeModule();
StatemachineFXModule fxModule = new StatemachineFXModule(Executors.newFixedThreadPool(3));
return Guice.createInjector((Module)runtimeModule, webModule);}
}.createInjectorAndDoEMFRegistration();
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx & Xtext‣ Step 3: Create a content assist provider
@Singletonpublic class ContentAssistProvider {
@InjectProvider<ContentAssistContextFactory> contextFactoryProvider;@InjectProvider<XtextResourceSet> resourceSetProvider;@InjectExecutorService pool;
public List<ICompletionProposal> doContentAssist(String content, String uri, Integer offset) {XtextResource resource = getResource(uri);
ContentAssistContextFactory contextFactory = contextFactoryProvider.get();contextFactory.setPool(pool);ContentAssistContext[] contexts = contextFactory.create(content, new TextRegion(0, 0), offset, resource);
List<ICompletionProposal> proposal = new ArrayList<>();for (int i = 0; i < contexts.length; i++) {
for (AbstractElement abstractElement : contexts[i].getFirstSetGrammarElements()) {createProposals(contexts[i], abstractElement, offset, proposal);
}}
return proposal;}
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
‣ Step 4: Setup Content assist in SourceViewerConfiguration
public class StatemachineSourceConfiguration extends SourceViewerConfiguration {public StatemachineSourceConfiguration(Document doc, File f) {
contentAssistProvider = injector.getInstance(ContentAssistProvider.class);}
@Overridepublic IContentAssistant getContentAssist() {
return new ContentAssistant(this::computeProposals);}
private List<ICompletionProposal> computeProposals(Integer offset) {return contentAssistProvider.doContentAssist(doc.get(),f.toURI().toString(), offset);
}}
FX & efx & Xtext
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
FX & efx & Xtext
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Compensator
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Compensator‣ Mission 0: Must look slick!
‣ Mission 1: Create a simple source editor like Notepad++ who:
‣ Is process light-weight
‣ Makes it easy to add new language highlightings
‣ Mission 2: Allow the simple source editor to expand to a (simple) IDE:
‣ where Source-Editor, VCS (git), Ticketsystem (eg. github), CI (eg. travis) are core components fully integrated with each other
‣ Easy to integrate: Does not depend on core.resources
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Compensator
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Python { partition __dftl_partition_content_type partition __python_multiline_comment partition __python_singleline_comment partition __python_string rule_damager rule_damager __dftl_partition_content_type { default token python_default token python_string token python_operator token python_bracket token python_keyword_return token python_keyword keywords python_keyword_return [ "return" ] keywords python_keyword [ "and", "as", „assert", /* … */] } rule_damager __python_singleline_comment { default token python_single_line_comment } /* … */ rule_partitioner { single_line __python_string '"' => '"' single_line __python_singleline_comment "#" multi_line __python_multiline_comment "'''" => "'''" single_line __python_string "'" => "'" }} for "text/python"
Compensator - HSL+CSS
/* */.Python.styled-text-area .python_doc_default {
-styled-text-color: rgb(63, 95, 191);}
.Python.styled-text-area .python_single_line_comment {-styled-text-color: rgb(63, 127, 95);
}/* */
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Demo
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Compensator
(c) BestSolution.at - Licensed under Creative Commons Attribution-NonCommerical-ShareAlike 3.0
Future‣ Add MWE Addon to
‣ Generate pure JavaFX integration
‣ Generate Compensator integration
‣ Add support for more services as they get available through the IDE-Agnostic APIs