Partial HTML generation from textile using eclipse Mylyn standalone

The title is pretty much explicit. For SlideshowFX, I needed to generate HTML content from textile, in order to define slide’s content. Looking for a lib, I found eclipse Mylyn that can be used in a standalone way. The library is pretty powerful but I have to look a lot at the sources in order to get the things done how I wanted to (#LukeAtTheSource power). Generally to convert a markup string into a HTML one, you create a MarkupLanguage as well as a MarkupParser and do the following:

final MarkupLanguage language = new TextileLanguage();
final MarkupParser parser = new MarkupParser(language);
parser.parseToHTML("h1. My little String");

The thing is that this code will create a whole HTML document (with html, head, body and so on tags). Me needs were to just get the HTML code corresponding to my string, e.g.

<h1>My little String</h1>

So the code should be changed to use a DocumentBuilder, like the following one:

final StringWriter writer = new StringWriter();
final DocumentBuilder builder = new HtmlDocumentBuilder(writer);
final MarkupLanguage language = new TextileLanguage();
final MarkupParser parser = new MarkupParser(language, builder);

// false indicates to not produce a whole HTML document
parser.parse("h1. My little String", false);

writer.flush();
writer.close();

String htmlContent = writer.toString();

This is almost done except that Mylyn generates IDs (which is kind of normal right?) by using the content of the markup. In short, I wanted to avoid IDs’ generation but I could’t find a right and efficient way to do it. So I decided to ensure uniqueness of IDs by always getting the current timestamp. Maybe it’s not a wonderful solution, but for the purpose of this little tutorial it will be perfect. The main idea is to change the ID generation and for doing this, you have to override some classes, because the default ID generation strategy is stored as a static and final variable, and no setters are available. The following example demonstrates how to do it:

final StringWriter writer = new StringWriter();

// The generation strategy generates IDs using the current timestamp
final IdGenerationStrategy idGenerationStrategy = new IdGenerationStrategy() {
  @Override
  public String generateId(String s) {
    return System.currentTimeMillis() + "";
  }
};

final IdGenerator idGenerator = new IdGenerator();
idGenerator.setGenerationStrategy(idGenerationStrategy);

final TextileContentState contentState = new TextileContentState() {
  @Override
  public IdGenerator getIdGenerator() {
    return idGenerator;
  }
};

// Override the language to return the created contentState used for the ID generation
final MarkupLanguage language = new TextileLanguage() {
  @Override
  protected ContentState createState() {
    return contentState;
  }
};

final DocumentBuilder builder = new HtmlDocumentBuilder(writer);

final MarkupParser parser = new MarkupParser(language, builder);

parser.parse(markupString, false);

writer.flush();
writer.close();

final String htmlContent = writer.toString();

This is it. Enjoy.

Advertisements

Update your Scene in JavaFX

Usually it is very simple to update your scene in JavaFX. For example if you want to update the X and Y position of your nodes, you can often simply do some stuff like:

node.setLayoutX(100d);
node.setLayoutY(150d);

But this isn’t a good way of doing it. In JavaFX you have to be sure you are in the JavaFX application thread. But how can you know this?

Platform.isApplicationFxThread();

But what if you’re not in that thread?

Platform.runLater(Runnable r);

So each time you would like to update your scene manually, you should check if you’re or not in the FX application thread. So let’s make a really simple helper class:

/**
 * @author Thierry Wasylczenko
 */
public class PlatformHelper {

    public static void run(Runnable treatment) {
        if(treatment == null) throw new IllegalArgumentException("The treatment to perform can not be null");

        if(Platform.isFxApplicationThread()) treatment.run();
        else Platform.runLater(treatment);
    }
}

The method run does the check for you. Finally you can use a lambda expression to execute that code:

final Node node = ... ;
PlatformHelper.run(() -> {
  node.setLayoutX(100d);
  node.setLayoutY(150d);
});

That’s it.

PathTextField: quick example of property usage in JavaFX

Context

Properties and binding in JavaFX is a really interesting feature that sometimes is hard to illustrate. Recently I just faced a problem in CompilerFX: file paths entered by the user could be problematic. Indeed on some platforms path separator is \ and on others it is /. In Java you can often use / as path separator.

Practice

So in our example, you can choose many solutions like for example:

  • When the user submit the path in a text field, replace all \ by /;
  • When the user enter a \, use a key event to replace it;
  • Choose a more JavaFX way.

Let’s deal with the third solution. Have this ones in mind:

  • In JavaFX you have the properties, allowing you to listen for a change using a ChangeListener;
  • The text of a TextField is store in the text property.

You could implement the second solution listen previously but let’s work with a custom text field that will replace replace all \ by /.

public class PathTextField extends TextField {

  {
    textProperty().addListener(new ChangeListener<String>() {
      @Override
      public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
        if(!textProperty().isBound() && s2 != null) {
          textProperty().set(s2.replaceAll("\\\\", "/"));
        }
      }
    });
  }
}

In this component, we place a ChangeListener on the text property in order to replace all \ by /. Then you can use it in your FXML files for example.

“Bind” components’ size to a MediaView’s size in JavaFX

The MediaView is a control allowing you to add videos and sounds to your JavaFX application. If you are playing a video, maybe you would like another control to have the same size. For example, you can have a video played next to an image that you would like to have the same height. The easy thing would like to do some property binding like this:

final MediaView mediaView = new MediaView(aPlayerInstance);
mediaView.setFitWidth(200);

final ImageView imageView = new ImageView(anImageInstance);
imageView.fitHeightProperty().bind(mediaView.heightProperty());

But this code is wrong because the MediaView doesn’t have a height property. So in order to succeed in our goal, the MediaView has a boundsInLocalProperty which can be used to change the size of the ImageView in our case. Look at this code example:

final MediaView mediaView = new MediaView(aPlayerInstance);
mediaView.setFitWidth(200);

final ImageView imageView = new ImageView(anImageInstance);

mediaView.boundsInLocalProperty().addListener(new ChangeListener<Bounds>() {
  @Override
  public void changed(ObservableValue<? extends Bounds> observableValue, Bounds bounds, Bounds bounds2) {
    imageView.setFitHeight(bounds2.getHeight());
  }
});

Of course you have to do some nullity checks to make your code more robust.

Working with NetBeans 7.3 and JavaFX 8

Maybe you want to work with the latest version of NetBeans, currently 7.3. But also with the early access of JDK 8 in order to play with the latest features of JavaFX. The thing is that NetBeans will not launch your JavaFX application, even if you are using JDK 7. Indeed you will get an exception dealing with Nashorn.

java.lang.VerifyError: Code generation bug in "runScript": likely stack misaligned: java.lang.ArrayIndexOutOfBoundsException: 0 <eval>
	at jdk.nashorn.internal.codegen.CodeGenerator.leave(CodeGenerator.java:1003)
	at jdk.nashorn.internal.ir.FunctionNode.accept(FunctionNode.java:339)
	at jdk.nashorn.internal.codegen.CompilationPhase$7.transform(CompilationPhase.java:239)
	at jdk.nashorn.internal.codegen.CompilationPhase.apply(CompilationPhase.java:372)
	at jdk.nashorn.internal.codegen.Compiler.compile(Compiler.java:263)
	at jdk.nashorn.internal.runtime.Context.compile(Context.java:758)
	at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:720)
	at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:358)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:463)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:451)
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:379)
	at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:134)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:487)
	at org.apache.tools.ant.util.ReflectUtil.invoke(ReflectUtil.java:108)
	at org.apache.tools.ant.util.ReflectWrapper.invoke(ReflectWrapper.java:81)
	at org.apache.tools.ant.util.optional.JavaxScriptRunner.evaluateScript(JavaxScriptRunner.java:103)
	at org.apache.tools.ant.util.optional.JavaxScriptRunner.executeScript(JavaxScriptRunner.java:67)
	at org.apache.tools.ant.taskdefs.optional.Script.execute(Script.java:52)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
	at sun.reflect.GeneratedMethodAccessor74.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:487)
	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.taskdefs.Sequential.execute(Sequential.java:68)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
	at sun.reflect.GeneratedMethodAccessor74.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:487)
	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.taskdefs.MacroInstance.execute(MacroInstance.java:398)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
	at sun.reflect.GeneratedMethodAccessor74.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:487)
	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.Target.execute(Target.java:392)
	at org.apache.tools.ant.Target.performTasks(Target.java:413)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
	at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:283)
	at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:541)
	at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:153)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 0
	at jdk.internal.org.objectweb.asm.Frame.merge(Frame.java:1408)
	at jdk.internal.org.objectweb.asm.Frame.merge(Frame.java:1364)
	at jdk.internal.org.objectweb.asm.MethodWriter.visitMaxs(MethodWriter.java:1382)
	at jdk.nashorn.internal.codegen.MethodEmitter.end(MethodEmitter.java:198)
	at jdk.nashorn.internal.codegen.CodeGenerator.leave(CodeGenerator.java:1000)
	... 50 more

The problem is that NetBeans uses the most recent JDK installed on your machine to run itself. And if you look in the About NetBeans menu entry, you will see that it uses the JDK 8 if it is installed, even if your JAVA_HOME points to your JDK 7 installation.

NB_JDK7

But there is a little workaround to get things working again: you can specify, in a configuration file of NetBeans, which JDK it should use. On OSX, show the package content of NetBeans 7.3.app and go to Content > Resources > NetBeans &gt etc and open the file netbeans.cnf. In this file, locate the line containing netbeans_jdkhome and uncomment it and specify the JDK home you want NetBeans to use. For example:

netbeans_jdkhome="/Library/Java/JavaVirtualMachines/Current/Contents/Home"

Then just restart NetBeans and go the About NetBeans menu entry. You should see that your JDK 7 installation instead of JDK 8.

NB_JDK8

Now if you try to launch your JavaFX application, everything is working again.

Set custom font in JavaFX 2

Maybe you would like to set custom fonts to your application for various reasons: make it touchy, be compliant with your corporation with corporate font, and so on. In JavaFX it’s pretty easy to change the font of a component. You can use the Labeled#setFont(Font f) method in your code, or define the -fx-font-family in your CSS. But what about custom fonts?

Load the font

The first thing you have to do is load the font. This is done like this:

Font.loadFont(SomeApp.class.getResource("/com/twasyl/someapp/font/MyFONT.TTF").toExternalForm(), 12);

This loads your font, which has a family, let’s say Thierry Font. This method makes the font available in your graphics environment and you just have to use it whenever you want. I like to place this code in my Application class, especially in the init method, so the I’m sure the font is loaded before any other treatment (especially before any labeled element is rendered). Let’s write this code:

public class SomeApp extends Application {

  @Override
  public void start(Stage stage) throws Exception {
    // Do some stuff
  }

  @Override
  public void init() throws Exception {
    super.init();

    Font.loadFont(SomeApp.class.getResource("/com/twasyl/someapp/font/MyFONT.TTF").toExternalForm(), 12);
  }

  public static void main(String[] args) {
      SomeApp.launch(args);
  }
}

Use your custom font

Punctual use

Either in your FXML or CSS code, you can now define the -fx-font-family with the value Thierry Font.

<Label style="-fx-font-family: 'Thierry Font'" />

This label will use the font, but what about the others elements? Do I really have to do this on ALL elements? Of course not …

General use

The interesting part is you can define your font for the whole application by default. Indeed in your CSS you just have to do this:

.root {
  -fx-font-family: 'Thierry Font';
  -fx-font-size: 15pt;
}

By default every labeled element will use your custom font. And of course you can change the font for a particular label again, using the style attribute for example.

TweetWallFX – Part 3

Hi,

Comparing to the two first parts, this article is going to propose some tips as well as some ideas that maybe could be interesting to see in JavaFX (JavaFX team members, keep reading). Well it seems to be cleared that since I took a look int JavaFX at Devoxx France I became a true fan (JavaFX team members: you simply rock by creating this version 2)! And when you start looking at it, just be honest, it’s an amazing technology! I’ll be talking in this article about transitions and FXMLLoader. Those topics are used in TweetWallFX to simplify some developments.

Transitions and animations

Since JavaFX 1 it is possible to create some transitions, animations on Node: fade in/out effects, sequential transition, rotations, scale, … and very complex ones! JFX is kind of open. Let’s take an example of fade in/out animation:

Label label = new Label("Fade me in");
// Create a transition that will apply on the label and during 1 second
FadeTransition fadeIn = new FadeTransition(new Duration(1000), label);
fadeIn.setFromValue(0);
fadeIn.setToValue(1.0);
// Go!
fadeIn.play();

label.setText("Fade me out");
FadeTransition fadeOut = new FadeTransition(new Duration(1000), label);
fadeOut.setFromValue(1.0);
fadeOut.setToValue(0);
fadeOut.play();

Well, the fade in and out code are the same except the From and To values. So let’s make it more scalable and in the way to be some “utils” methods.

public static void fadeOut(Node node, double duration) {
  getFadeOutAnimation(node, duration).play();
}

public static void fadeIn(Node node, double duration) {
  getFadeInAnimation(node, duration).play();
}

public static FadeTransition getFadeInAnimation(Node node, double duration) {
  return getFadeAnimation(node, duration, node.getOpacity(), 1.0);
}

public static FadeTransition getFadeOutAnimation(Node node, double duration) {
  return getFadeAnimation(node, duration, node.getOpacity(), 0.0);
}

private static FadeTransition getFadeAnimation(Node node, double duration, double fromValue, double toValue) {
  FadeTransition fadeTransition = new FadeTransition(new Duration(duration),
                node);
  fadeTransition.setFromValue(fromValue);
  fadeTransition.setToValue(toValue);
  return fadeTransition;
}

Easy right? As you can see, the fromValue is the current opacity of the Node because the FadeTransition is updating this value while the transition is played. So instead of asking everytime the from value, we just take the current opacity, which seems logical.
Now on the same basis we will create a simple transition which will translate a Node horizontally and/or vertically.

/** We will move the node from the given number of horizontal and vertical pixels */
public static void move(Node node, double duration, double numberOfHorizontalPixels, double numberOfVerticalPixels) {
  getMoveAnimation(node, duration, numberOfHorizontalPixels, numberOfVerticalPixels).play();
}

public static Timeline getMoveAnimation(Node node, double duration, double numberOfHorizontalPixels, double numberOfVerticalPixels) {
  KeyValue horizontalMove = null, verticalMove = null;

  if (numberOfHorizontalPixels != 0) {
    // This represents the final horizontal position of the Node:
    // Current position + "deltaX"
    horizontalMove = new KeyValue(node.layoutXProperty(),
                     node.getLayoutX() + numberOfHorizontalPixels);
  }
  if (numberOfVerticalPixels != 0) {
    // This represents the final vertical position of the Node
    // Current position + "deltaY"
    verticalMove = new KeyValue(node.layoutYProperty(),
                   node.getLayoutY() + numberOfVerticalPixels);
  }
  // KeyFrame are like the interpolation frames in Flash ...
  KeyFrame kf = new KeyFrame(new Duration(duration), horizontalMove, verticalMove);
  // The timeline will play every given KeyFrame
  Timeline timeline = new Timeline(kf);
  // Play the animation once
  timeline.setCycleCount(1);

  return timeline;
}

If you are familiar with Flash development, you may recognize some concepts here. The timeline is globally the same as the timeline in Flash. The KeyFrame is a developer defined position of an object, defined by KeyValues. In Flash, you will do an interpolation, and the last image of this interpolation is defined by you, developer. And the intermediate images (frames) are managed and computed by the engine. In JavaFX, same concept. If you’re more interested in the animations, there’re some others that you can read on the JavaFX page.

FXMLLoader

FXML files are loaded using a FXMLLoader. You have two main ways of loading such files. The first one is using the static load() method which will return you the root component of your FXML file.

// I don't manage exceptions in this example
URL url = getClass().getResource("/some/package/yourFile.fxml");
Parent root = FXMLLoader.load(url);

This is useful when you don’t really need the controller. The second way is to create an instance of FXMLLoader that allows you to, of course, get the root element of your file, as well as the controller.

// I don't manage exceptions in this example
URL url = getClass().getResource("/some/package/yourFile.fxml");
FXMLLoader loader = new FXMLLoader(url);
Object root = loader.load();
Object controller = loader.getController();

Pretty straight forward. I have an idea for maybe future version of JavaFX (if any JavaFX team members reading, this one’s for you). I don’t know if it would be possible to create like a FXML library. Indeed, I looked the sample apps provided with JavaFX and I saw that the FXML is in the same package as the controller for example, or more generally, there is a package for a functionality. I pretty like this approach, kind of well organizing your architecture. But I usually like to hava same kind of elements in the same place, for example a package for all of my FXML files, another one for my controllers and so on. I really think it is the way you like to organize your code that matters. But anyway, in TweetWallFX a lot of FXML files are there and I said to myself “Well would be great if I had some kind of FXML library”. And I created a really basic one:

public class FXMLLibrary {
  private static final String BASE_PACKAGE = "/com/twasyl/tweetwallfx/fxmls/";
  public static final String TOOLTIP_FXML = BASE_PACKAGE + "tooltip.fxml";
  public static final String TWEETWALLFX_FXML = BASE_PACKAGE + "TweetWallFX.fxml";
  public static final String TWEETBUBBLE_FXML = BASE_PACKAGE + "TweetBubble.fxml";
  public static final String STATISTICS_TAB_FXML = BASE_PACKAGE + "statistics-tab.fxml";
  public static final String STATISTICS_LOOKUP_FXML = BASE_PACKAGE + "statistics-lookup.fxml";
  public static final String WALL_TAB_FXML = BASE_PACKAGE + "wall-tab.fxml";
  public static final String APPLICATION_MENUBAR_FXML = BASE_PACKAGE + "application-menubar.fxml";
  public static final String MUSIC_PLAYER_FXML = BASE_PACKAGE + "music-player.fxml";
  
  public static URL getFXMLUrl(String fxml) {
    return FXMLLibrary.class.getResource(fxml);
  }
}

So if I need to use a particular FXML file in different places, I just need to update the URL in one place if needed. And I am wondering if such a library could be provided by default. I’m coming from the JSF world and in JSF apps you have the faces-config.xml file which contain some context-param, resource bundles and so on. Maybe in JavaFX we could have a jfx-config.xml file with some properties (like resource bundles in JSF) with some maven ideas also, like this:

<jfx-config>
  <properties>
    <base-package>/com/twasyl/tweetwallfx/fxmls</base-package>
  </properties>
  <fxmls>
    <fxml>
      <name>TOOLTIP_FXML</name>
      <url>${base-package}/tooltip.fxml</url>
      <bundle>/com/twasyl/tweetwallfx/resources/i18n/tooltip</bundle>
    </fxml>
    <fxml>
      // ...
    </fxml>
  </fxmls>
</jfx-config>

And the FXMLLoader could be based on the names provided in the config file. I don’t know if this is relevant, I just got the idea. Well that’s it for this article, stay tuned.