I haven’t done an update for a while. This has been deliberate. Towards the end of 2018 I was working on modifying a project called LanguageTool so that it could be used in QW for spellchecking and other language rule checking. I finished modifying the project, you can find it here, in essence I removed a number of arcane restrictions that LanguageTool has for its use, such as having to have ALL files for ALL languages you might use always available at ALL times. In short, you couldn’t download new and use languages if they weren’t already installed and only available in a specific place.
Changing LanguageTool was a mentally draining exercise, it was a huge chunk of work but it’s done and ready for use in the future.
However for a couple of years now I’ve been looking to the future for QW. At present it uses Java Swing as the underlying GUI technology. Swing is old, very old, and it’s not being actively developed or maintained by Oracle (the owners of Java). Instead Oracle have been working on a new GUI framework called JavaFX. This takes a more modern approach and uses things like stylesheets for modifying how the UI looks, in a similar way to HTML.
So a couple of years back I looked at moving QW to use JavaFX but that was a hard fail. You see the reason I initially used Java Swing for QW was a component called JTextComponent. This is a Swing component that lets you display and manipulate text. It also has great features like allowing you to get a position in the text and find out where it is on screen and vice versa. You can also track a position or offset within the text, so when the user types the position changes. The combination of these features enable the QW icon column to exist.
But there was a problem with JavaFX, it didn’t have a similar text component. But it did allow Swing components to be used and displayed within JavaFX. So I did some tests and got a text component working within a JavaFX GUI but there was a problem. JavaFX wouldn’t pass focus to the the Swing component properly. In essence you couldn’t always click on the text component and if you did you couldn’t then click on a JavaFX component. Annoyed I looked for another text solution. Luckily I found RichTextFX which is a sort of replacement for JTextComponent that someone created for JavaFX. However, while it is a great component it was lacking the necessary features I needed to make the icon column work. I could add those features and I actually started to do so but I would have to become an expert in something new and I eventually got sidetracked with making the Language Strings Editor for QW that allows users to create translations of the UI for QW. Also my confidence in RichTextFX wasn’t great, the original developer had abandoned the project and the current maintainer is actively looking to give the project up. In essence I would have to create and maintain my own version of the RichTextFX component and I don’t have time for that. I may eventually have to do that but I can’t justify the time at the moment.
Deflated I eventually gave up on moving QW to JavaFX but at the start of this year and wanting to do something that wasn’t LanguageTool related I tried again at moving QW to JavaFX. This time I wanted to know if the focus bug had been fixed and it seems it has! So I present to you the first images of the very first alpha version of QW3.
I know they are nothing to look at. They are proof of principle examples. In the first image that is actually the same component used for chapter editing that is present in the current QW version but it is embedded in a JavaFX UI. The second image is the list of projects but it is currently unstyled so it looks naff, the important thing there is that the data is correct.
So what does this all mean?
In short this means that I am giving up on all other QW development and working on version 3 of QW. I can finally, mostly, give up on Java Swing (which I’ve always hated) and move to a newer framework that is far easier to use and work with. Seriously the fights I’ve had with Java Swing over the sizing of components would make Godzilla cower with fright.
So what benefits will this bring? The list is almost endless but here’s a few I foresee:
- Native Linux and Mac versions.
- Infinite styling choices. You the end user will be able to pick how QW looks, you will be able to pick your own stylesheet to use. It also means that end users will be able to create their own stylesheets and make them available to others.
- Switchable, time based styling. Introducing a night mode (a frequently requested feature) will now be trivial and I can make certain stylesheets available at certain times.
- Support for markdown in descriptions. JavaFX has full support for modern CSS styling so allowing for markdown in descriptions will be easy to add.
- Inline web page viewing. Again JavaFX has an excellent, full featured web page viewer so instead of just having links HTML content can be visible within the app. This also has the potential to make the user guide available within the app itself.
- Real time updating of the UI language. JavaFX allows you to bind the text displayed in a component to a property within the system. When the value of the property changes the text will change. I have already implemented this.
- Better and more varied UI components. I will finally be able to created a timeline planning tool. I tried in vain to make one happen in Swing.
Sounds great, when will version 3 be available?
In short, I don’t know. QW is a big application now and it does a lot, it’s going to take time to rework everything. I’m going to tentatively say a beta version should be available by July-ish 2019 but this is a date I’ve plucked out of the air. I don’t really know, this is all new and changing over an existing application to a new framework is an unknown quantity. Some things that were possible may not be possible, some things may need to be rethought altogether, I don’t know yet.
For now watch this space, I’ll be doing regular updates on how things are progressing.
The rest of this post will be talking about detailed Java code stuff so feel free to skip it.
Benefits for me
There will also be numerous benefits for me (i.e. the guy doing the work).
I want to make use of the more modern features available to Java such as lambdas and functional programming, this will speed me up and reduce the amount of code I have to produce.
For instance, instead of writing:
button.addListener (new ActionListener ()
public void actionPerformed (ActionEvent ev)
I can now write:
button.onAction (() -> doSomething ());
All that horrible boilerplate is gone and it’s far easier to see what is actually happening.
I’m also starting to make heavy use of streams and the newer APIs such as java.nio.file.
So instead of having a standard for loop for processing a set I can chain functions together for a more holistic approach, for example:
Files.walk (start, 0)
.map (f -> createAThing (f))
.filter (f -> f != null)
.collect (Collectors.toSet ());
This is far easier and less wordy than the normal processing. But to be clear I could have used this type of programming in earlier versions of QW but steered away from it because I didn’t want to have multiple methods of doing the same thing with a half-n-half approach but since I am reworking QW from the ground up I can introduce better ways of doing things.
I am also making heavy use of the builder pattern for creating the basic components that will be visible in the UI. Generally when creating GUI components you wind up with this type of code:
MyComponent comp = new MyComponent ();
This tends to be error prone and difficult to read, the builder pattern alleviates this and makes it easier to build components, i.e.
MyComponent comp = MyComponent.builder ()
It is far easier to see what is actually going on and reduces the amount of code which is always good.
JavaFX has the concept of “Properties” which replaces (mostly) the Swing concept of events and listeners. Generally when one thing changes in a UI, you want another aspect of the UI to change to reflect this. For example in the Projects window, if you add another project, the title of the window has to change to reflect the new number of projects. Currently in QW I have to spend a lot of time firing off events and adding listeners for those events to react to changes. JavaFX properties removes that by allowing me to “bind” properties together, thus when the “projects” property changes the “title” property of the window will be updated automatically. I don’t need to do anything special, only bind those properties together, i.e.
this.titleProp.bind (Bindings.createStringBinding (() ->
return String.format (getUIString (LanguageStrings.allprojects, LanguageStrings.title), Environment.formatNumber (Environment.allProjectsProperty ().size ()));
UILanguageStringsManager.uilangProperty (), Environment.allProjectsProperty ()));
This bit of code is saying that if the UI language property changes (i.e. what language the UI is using) or if the all projects property changes (i.e. a project is added or removed) then update the title property to a new value. So instead of worrying about the title I now only have to worry about changing the relevant properties and everything that is bound to those properties will automatically change. Simples!
Also, because I’m using a builder pattern I can actually enforce the use of properties so I can’t forget to set up the correct string for a component. For example:
return QuollButton.builder ()
.onAction (ev -> this.runCommand (Command.reportbug))
Here I am passing a number of string ids to the “tooltip” for the button. You can think of these ids as an index into a data structure that stores the strings. So “project” is the subset of strings for project windows, “title” is the subset of strings for the title within the project subset and so on. The tooltip method on the builder then takes those string ids and converts them to a property that is dependent on the UI language property, when that changes, the tooltip value is updated automatically.
Another change I’m making is to make use of functional interfaces and the java.util.function package. This allows me to reduce the number of interfaces and classes I have. Combined with the builder pattern it allows me to also reduce the number of abstract methods I have. So instead of this:
public class MyUIClass implements MenuItemProvider
public abstract Set<MenuItem> getMenuItems ();
Where I have to create a subclass and override the method I can now have:
public static class Builder
public Builder menuItems (Supplier<Set<MenuItem>> items)
this.itemSupplier = items;
The practical upshot being that I can now do:
.menuItems (() -> generateMenuItems ())
In reality I would probably replace the generateMenuItems call with the actual code that is creating the items.
Another long standing issue I’ve wanted to solve is the separation of the GUI component from the GUI component that is actually displaying/managing it. So instead of every sidebar having to subclass AbstractSideBar, I now have a SideBar component that has some content and uses a builder to create the sidebar.
Now a lot of this work has already been done, just to get to the prototype I’ve had to put a substantial amount of the underlying framework in place.
But there are still a huge number of issues to solve. You probably didn’t notice but there was no scrollbar in the project image above and there should have been. This is a problem with the way that the component is being updated, I need to fix that. I also need to get the styling started. I am already adding styles to each component but the stylesheet I’m currently using doesn’t reflect that.
So I’ve a long way to go but I’ll get there! Watch this space for updates.