Getting started with Java and creating an AsciiDoc editor with JavaFX

I made an AsciiDoc editor

Click here for the finished product AsciidocEditor ezgif.com-optimize.gif

As well as live preview, some settings of ascii doctor and ace editor can be manipulated from GUI, and ascii doctor's default CSS and source highlighter CodeRay's CSS are brought locally. , If you are strong in CSS, you can use your favorite design.

Motivation

I'm usually a college student. I started programming after I entered university, and until then I hadn't even touched a computer. The only thing I've been doing in practice since I entered the school is learning algorithms and writing in C language. I think it's important and interesting to learn and implement algorithms. However, I have come to feel that it is not enough. So I decided to make a GUI application.

Flow to completion

First semester (learning)

* Skills before starting to make

I'm used to C language, but I haven't learned much about Python because it has a template.

Getting started with Java

The faculty member said something like "At least one procedural type and one object-oriented type should be touched." So I'm not very familiar with programming languages, so when it comes to object-oriented, the mystery of Java !! With that in mind, I decided to get started with Java.

I bought it because it was recommended in various places. It was easy to read and organized according to its reputation, and I was able to imagine object-oriented programming.

Preliminary research

After reading the above introductory book, I felt like getting started, so I checked the Java GUI library. What we learned at this stage is as follows.

Mid-term (mid-slack)

As a result of the preliminary research, I thought that I had made a difficult language selection. I thought it would be difficult to collect information because JavaFX would not be included in the JDK.

Late (implementation)

Since I started with a lot of effort, I will reconsider making it.

What to make

At the time of the preliminary survey, some people implemented the markdown editor easily, so I thought about adding the original element to something similar. As I researched various things, I found out about the existence of AsciiDoc. Let's make an AsciiDoc editor! And here is the function of the strongest AsciiDoc editor that I thought of

If you make this, it's only one! !!

... that wasn't the case. : innocent: AsciidocFX I think there are other great things, but I aimed to add features that Asciidoc FX does not have to the above features. AsciidocFX can fill the editor frame, but not the preview screen. It turns out that even if you specify toc: left and the position of the table of contents, you cannot see it in the preview. (Maybe it can be done ...)

Therefore, the final specifications are as follows.

I will introduce the part where development was delayed due to a slight catch.

Basic function of the editor

In JavaFX, the FileChooser class is used to read and save files.

FileChooser fileChooser = new FileChooser();
File file = fileChooser.showOpenDialog(null);

The problem was the null passed to the argument on the second line, and when I displayed the app in full screen, it stopped responding and I had to kill it. Instead, pass the main Stage as an argument. A sample that inherits the common Application class

public class Sample1 extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader();
        Parent root = fxmlLoader.load(getClass().getResourceAsStream("/sample1.fxml")); 
        primaryStage.setTitle("sample 1");
        primaryStage.setScene(new Scene(root, 900, 600));
        primaryStage.show();
    }
}

But this

public class Sample2 extends Application {

    static Stage stage;

    public static void main(String[] args) {
        launch(args);
    }
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader();
        stage = primaryStage;
        Parent root = fxmlLoader.load(getClass().getResourceAsStream("/sample2.fxml")); 
        stage.setTitle("sample 2");
        stage.setScene(new Scene(root, 900, 600));
        stage.show();
    }
}

Pass to FileChooser as

FileChooser fileChooser = new FileChooser();
File file = fileChooser.showOpenDialog(Sample2.stage);

This way, even if you move the main window, the FileChooser window will be attached. For the Dialog class

Dialog<ButtonType> dialog = new Dialog<>();
dialog.initOwner(Sample2.stage);

You can do the same with.

Live preview (AsciiDoc-> HTML)

Library used

asciidoctorj makes the Ruby library asciidoctor available in Java. The string generated from this is poured into JavaFX's WebView. I didn't find many examples using asciidoctorj-diagram, so I will write it for reference.

Asciidoctor asciidoctor = org.asciidoctor.Asciidoctor.Factory.create();

After creating an instance with

asciidoctor.requireLibrary("asciidoctor-diagram");

Then you can use functions such as plantuml.

Problem 1: Local image is not displayed

JavaFX WebView can be loaded and displayed by the load method or loadContent method of WebEngine. This time we'll load the raw HTML as a String instead of a URL, so we'll use the loadContent method. However, when I load the HTML with this method, it doesn't display the local image in the path of the src attribute. All I needed was to have the file protocol file: // in mind. I used jsoup to solve this problem.

ArrayList<Element> src = document.getElementsByAttribute("src");
for (Element e : src) {
            String attributeValue = e.attr("src");
            if (!attributeValue.contains("data:") &&
                !attributeValue.contains("https:") &&
                !attributeValue.contains("file:")
            ) {
                attributeValue = Paths.get(attributeValue).toUri().toString();
                e.attr("src", attributeValue);
            }
        }

The file protocol is attached by the toUri method.

Problem 2: Link related problem

When I click the link displayed in the WebView of JavaFX, it is loaded by that WebView, so I can't see the preview of AsciiDoc that I was originally looking at, albeit temporarily. To solve this, I opened it in the default browser.

//viewer is the fxml component of WebView for preview
viewer.getEngine().getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == Worker.State.SCHEDULED) {
                String urlLocation = viewer.getEngine().getLocation();
                if (urlLocation.contains("http:") || urlLocation.contains("https:")) {
                    viewer.getEngine().getLoadWorker().cancel();
                    try {
                        Desktop.getDesktop().browse(new URI(urlLocation));
                    } catch (URISyntaxException | IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

Another problem was the inability to jump within the page for the a tag. This time

viewer.getEngine().setJavaScriptEnabled(true);

By doing so, I made JavaScript executable, added a script tag with jsoup, and loaded the script for the anchor link.

String anchorLinkScript =
                "function anchorlink(id_name) {" +
                    "obj = document.getElementById(id_name);" +
                    "obj.scrollIntoView(true);" +
                "}";

        Element body = document.body();
        body.appendElement("script").append(anchorLinkScript);

        ArrayList<Element> elements = document.getElementsByTag("a");
        for (Element e : elements) {
            if (!(
                e.attr("href").contains("http:") ||
                e.attr("href").contains("https:")
            )) {
                String idName = e.attr("href").substring(1);
                e.attr("onclick", "anchorlink(\'" + idName + "\')");
            }
        }

* Japanese IM for Ace and Mac (already introduced in the previous article)

When I embedded Ace in JavaFX, the Japanese IM on Mac was buggy, so I solved it

I was able to implement some functions like this.

Things that haven't been done yet

Functional aspect

This time, it is converted every time you type a character, so if you use the asciidoctor-diagram function, a .png file will be generated every time you type a character. Moreover, I tried to give a file name to prevent it.

[plantuml, "sample"]
----
Bob->Alice: Hello
----

If you enter in order from the top, sample.png itself will change firmly every time you enter it, but WebView will only display the first generated sample.png (re-app It will be displayed when you start it, and the exported HTML will be loaded without any problem). I'm worried because I have no idea about this.

Another feature I wanted to include PDF output was.

Distribution side

Basically, I had a strong image that an app can be started by double-clicking the icon, so I aimed for that as well. Specifically, I wanted to distribute cross-platform apps by making full use of jlink, install4j, and badass-runtime-plugin. However, I felt that I would never be able to put out the deliverables in public unless I put them out as they are, so I gave up and released them. From Java 13, there may be a jpackage, so look forward to it!

Looking back

It's hard to make by yourself

I made this by myself without telling anyone, but after all, it took me four months to release it after creating the repository on GitHub. I made the repository after I thought about making the AsciiDoc editor, so it's been about 8 months since I started Java. Possible reason is

is. I always thought it would take a long time to code until I made this, but it took me several times longer to search for something I didn't understand and swallow it. Also, it was painful that no one was able to tell me how coding was customary in Java, spaghetti, or something that I wouldn't notice. Obviously, maintaining motivation is very important. This time there was a period of slack, and I didn't go as I expected, but I found that even small things can increase my motivation. I was happy every time I thought about small functions that AsciidocFX did not have, and since it was my first GUI, each one worked as expected.

It's important to read the official reference

Somehow, when I always do programming-related searches, I had a habit of coming to Qiita first. Qiita is easy because you can get the information you want to know quickly. However, if you want to make something from scratch, it may be important to look at the official documentation first. Since JavaFX 11 is no longer included in the JDK, I knew at first that there was a document Getting Started with JavaFX 11 for that. did not. It was very easy to understand (small average feeling). If I realized the greatness of the official reference a little earlier, I could have shortened the development period. After noticing it, I tried to look at the API documentation of the libraries that I use, including Java. If you have dozens of Firefox tabs open just in the official API docs, you're programming! !! I was excited to feel that. I think this also helped maintain motivation.

Summary

I challenged the first GUI in the language I touched for the first time. I wrote that it is difficult to do alone, but there is a good sense of accomplishment (I think that if you are not alone, you can share the sense of accomplishment, so I do not know which one).

If you're just starting out programming, like me, who read this, I recommend that you do some preliminary research before getting started in programming languages (which may be obvious ...). From the beginning of implementation, I think that you will be coding while researching, but it will surely be fun because you will find that the technology will be much better than reading the introductory book and writing examples. Eliminate your resistance to English and read the official docs, Stackoverflow, etc. (because Stackoverflow sometimes has strong people like crap).

And for the senior programmer who happened to see it to the end, I may not have written anything that would be helpful. If you are kind, please take a look at GitHub and encourage me to say "This source code is Akan !!". Also, such a language and library are interesting! Or, I wish I had read this before starting development ... I hope you can tell me an article like that (beggar).

When I read it back, it looks like "What number decoction and Nen", but thank you for reading to the end.

Recommended Posts

Getting started with Java and creating an AsciiDoc editor with JavaFX
Getting Started with Java Collection
Getting Started with Java Basics
Getting started with Java lambda expressions
Getting Started with Ruby for Java Engineers
Getting Started with Java Starting from 0 Part 1
Getting Started with Creating Resource Bundles with ListResoueceBundle
Getting Started with Java_Chapter 8_About Instances and Classes
Links & memos for getting started with Java (for myself)
Getting Started with Java 1 Putting together similar things
Getting started with Kotlin to send to Java developers
Getting Started with DBUnit
Getting Started with Ruby
Getting Started with Swift
Getting Started with Docker
Getting Started with Doma-Transactions
Getting started with Java programs using Visual Studio Code
Prepare the environment for java11 and javaFx with Ubuntu 18.4
Getting Started with Legacy Java Engineers (Stream + Lambda Expression)
Going back to the beginning and getting started with Java ① Data types and access modifiers
Make an Ev3 radio control with JavaFx and leJOS [Part 2]
Getting Started with Doma-Annotation Processing
Getting Started with Reactive Streams and the JDK 9 Flow API
Getting Started with JSP & Servlet
Getting Started with Spring Boot
Make an Ev3 radio control with JavaFx and leJOS [Part 1]
Getting Started with Ruby Modules
Building an environment for creating apps with Rails and Vue
Use java with MSYS and Cygwin
Distributed tracing with OpenCensus and Java
Install Java and Tomcat with Ansible
Java learning memo (creating an array)
Getting Started with Java_Chapter 5_Practice Exercises 5_4
About creating an application with springboot
Use JDBC with Java and Scala.
Hello world with Kotlin and JavaFX
[Java] Declare and initialize an array
[Google Cloud] Getting Started with Docker
Output PDF and TIFF with Java 8
Drag and drop files with JavaFX
Getting Started with Docker with VS Code
Run an application made with Java8 with Java6
Encrypt with Java and decrypt with C #
Getting Started with Micronaut 2.x ~ Native Build and Deploy to AWS Lambda ~
How to make an app with a plugin mechanism [C # and Java]
Getting Started with Machine Learning with Spark "Price Estimate" # 1 Loading Datasets with Apache Spark (Java)
Getting started with Gradle (until you create a Java project and combine external libraries into one executable JAR)
Getting started with Maven (until you create a Java project and combine external libraries into a single executable JAR)
Getting Started with Doma-Criteria API Cheat Sheet
Create an infinite scroll with Infinite Scroll and kaminari
[Java] Create an executable module with Gradle
Monitor Java applications with jolokia and hawtio
Link Java and C ++ code with SWIG
Let's try WebSocket with Java and javascript!
Getting Started with Docker for Mac (Installation)
[Java] Reading and writing files with OpenCSV
Getting Started with Parameterization Testing in JUnit
Scaling and translation with JavaFX Canvas (Revenge)
Getting Started with Ratpack (4)-Routing & Static Content
Getting started with the JVM's GC mechanism
Getting Started with Language Server Protocol with LSP4J