Restoring window sizes in JavaFX

When doing usability testing of an alpha version of Dashman, one thing that I was strongly asked was to have the windows remember their sizes when you re-open the application. The need was clear as it was annoying to have the window be a different size when re-started.

The new version of Dashman is built using Java and JavaFX and thus I searched for how to do this, how to restore size. I found many posts, forums, questions, etc all with the same simplistic solution: restoring width and height, and maybe position.

What those were missing was restoring whether the window was maximized (maximized is not the same as occupying all the available space, at least in Windows). But most important than that, none of the solutions took into consideration the fact that the resolutions and quantity of screens could be different than the last time the application run, thus, you could end up with a window completely out of bounds, invisible, immobile.

I came up with this solution, a class that’s designed to be serializable to your config to store the values but also restore them and make sure the window is visible and if not, move it to a visible place:

// Copyright (c) 2017 Flexpoint Tech Ltd. All rights reserved.

package tech.dashman.dashman;

import com.fasterxml.jackson.annotation.JsonIgnore;
import javafx.geometry.Rectangle2D;
import javafx.stage.Screen;
import javafx.stage.Stage;
import lombok.Data;
import tech.dashman.common.Jsonable;

@Data
public class StageSizer implements Jsonable {
    private static int MINIMUM_VISIBLE_WIDTH = 100;
    private static int MINIMUM_VISIBLE_HEIGHT = 50;
    private static int MARGIN = 50;

    private Boolean maximized;
    private Number x;
    private Number y;
    private Number width;
    private Number height;

    @JsonIgnore
    public void setStage(Stage stage) {
        // First, restore the size and position of the stage.
        resizeAndPosition(stage);
        // If the stage is not visible in any of the current screens, relocate it the primary screen.
        if (isWindowIsOutOfBounds(stage)) {
            moveToPrimaryScreen(stage);
        }
        // And now watch the stage to keep the properties updated.
        watchStage(stage);
    }

    private void resizeAndPosition(Stage stage) {
        if (getX() != null) {
            stage.setX((Double) getX());
        }
        if (getY() != null) {
            stage.setY((Double) getY());
        }
        if (getWidth() != null) {
            stage.setWidth((Double) getWidth());
        }
        if (getHeight() != null) {
            stage.setHeight((Double) getHeight());
        }
        if (getMaximized() != null) {
            stage.setMaximized(getMaximized());
        }
    }

    private boolean isWindowIsOutOfBounds(Stage stage) {
        boolean windowIsOutOfBounds = true;
        for (Screen screen : Screen.getScreens()) {
            Rectangle2D bounds = screen.getVisualBounds();
            if (bounds.getMinX() < stage.getX() && stage.getX() + MINIMUM_VISIBLE_WIDTH < bounds.getMaxX() &&
                    bounds.getMinY() < stage.getY() && stage.getY() + MINIMUM_VISIBLE_HEIGHT < bounds.getMaxY()) {
                windowIsOutOfBounds = false;
                break;
            }
        }
        return windowIsOutOfBounds;
    }

    private void moveToPrimaryScreen(Stage stage) {
        Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
        stage.setX(bounds.getMinX() + MARGIN);
        stage.setY(bounds.getMinY() + MARGIN);
        stage.setWidth(bounds.getWidth() - MARGIN * 2);
        stage.setHeight(bounds.getHeight() - MARGIN * 2);
    }

    private void watchStage(Stage stage) {
        // Get the current values.
        setX(stage.getX());
        setY(stage.getY());
        setWidth(stage.getWidth());
        setHeight(stage.getHeight());
        setMaximized(stage.isMaximized());
        // Watch for future changes.
        stage.xProperty().addListener((observable, old, x) -> setX(x));
        stage.yProperty().addListener((observable, old, y) -> setY(y));
        stage.widthProperty().addListener((observable, old, width) -> setWidth(width));
        stage.heightProperty().addListener((observable, old, height) -> setHeight(height));
        stage.maximizedProperty().addListener((observable, old, maximized) -> setMaximized(maximized));
    }
}

and the way you use it is quite simple. On your start method, you create or restore an instance of StageSizer and then do this:

public void start(Stage stage) {
    StageSizer stageSizer = createOrRestoreStageSizerFromConfig();
    stageSizer.setStage(stage);
}

I haven’t put a lot of testing on this code yet but it seems to work. Well, at least on Windows. The problem is that this snippet is interacting with the reality of screen sizes, resolutions, adding and removing monitors, etc. If you find a bug, please, let me know and I might release this a library with the fix so we can keep on collectively improving this.

Advertisements

Book Review: General Class by Gordon West

I bought this book after watching a series of videos on YouTube that mentioned it:

61i+nE392VLThe book has a short introduction and then jumps straight into the question pool for the general class amateur radio exam. For each question, you have the four potential answers, followed by an explanation of the subject and the correct answer. Because the questions and the answer are so close, you might need to use a piece of paper to cover the answer while you think about the question without spoiling it.

I did my study mostly by watching the video and using https://hamstudy.org but the explanations on that website, sometimes, leave a lot to be desire. For quite a few questions, reading the explanations in this book helped a lot. It also has extra snippets of information spread throughout the book that are very nice.

Another positive thing about this book is that it’s full color. It has pictures but most importantly, diagrams and chart making use of the color range to make the information more accessible. Even though I know by heart some of that information, I find myself hopping they would make posters of these charts so I can hang them on my shack: they are beautiful and informative.

Oh… one more thing, I passed the test. Well, I passed the three tests in one sitting.

★★★☆☆

Buy 2015-2019 General Class in USA
Buy 2015-2019 General Class in UK
Buy 2015-2019 General Class in Canada

Book Review: Amateur Radio Exam Secrets by Alan Betts

91lYFNMRVVLDisclaimer: I haven’t read it all, as I’m only going for the foundation level license so I only read the relevant sections and I’ll come back to it when I upgrade to other levels.

I bought this book without knowing anything about it and I’m so glad I did. The book covers all levels of amateur licences in the UK. The way it does it is that each chapter is divided in subsections for each of the levels, so, you can read each chapter up to level you are interested and move on to the next.

Each chapter contains a brief introduction to the subject followed by a set of sample questions like the ones you’d get in the exam. Unlike the American counterpart, the question pool in the UK is not public because you should learn the subject and not memorize answers. Having said that, having some mock tests really helps understand how well prepared you are. There’s even an extra set of questions towards the end.

The answers to all the questions are in an appendix almost at the very end of the book, so, it’s very convenient to avoid accidentally seeing the answer and losing the value of that question. I found thought that going back and forth was annoying and prone to seeing more answers than intended, so, I’d recommend for each section, to do all the questions by writing down the answers on a piece of paper and then checking them against the references.

At the very end of the book you also have the tables, band plan and references that you are allowed during the exam.

I highly recommend this book if you are going to take the exams.

★★★★☆

Buy Amateur Radio Exam Secrets in USA
Buy Amateur Radio Exam Secrets in UK
Buy Amateur Radio Exam Secrets in Canada

Trying to decide on a VHF/UHF radio

Next month, I’m taking my test to get a ham radio licence here in the UK. This is not my first licence. I’ve got LU5ARC years ago, as I was leaving Argentina, so, I never really got to use it. Years before that I’ve got a Yaesu FT411E, but I never transmitted with it due to lack of licence.

I don’t want that to happen again, so, as soon as I get my licence I want to hit the ground running and start using it. My plan right now is:

  1. Get a VHF/UHF hand held radio.
  2. Learn about antennas by reading:
  3. Get an antenna for VHF/UHF on my car (probably magnetic).
  4. Attempt to install a VHF/UHF vertical antenna in my house.
  5. Decide based on the information I have so far whether I can go for HF.
  6. Set up an HF base station.

Right now, I’m concerned about step 1. These are the things I’m after, in this order of preference:

  1. VHF
  2. UHF
  3. Ability to use a stationary vertical antenna
  4. Weather proofing
  5. D-Star (with GPS)
  6. APRS (with GPS)

I could try to get everything now, or maybe do it in stages. I’m not sure yet. I narrowed down my selection to these 5 radios:

  • Kenwood TH-D74
  • Icom ID-51 PLUS2
  • Icom IC-E91
  • Yaesu FT-60E
  • A Baofeng

Kenwood TH-D74

The ideal radio seems to exist and it’s the Kenwood TH-D74 (Buy: US). From what I’m seeing this piece of equipment is insane. It does everything and it does almost everything well (except maybe battery life). The price is also insane. If money was no object I would just get this radio and I’m done. I’d probably use it for many, many years.

Kenwood TH-D74

Icom ID-51 PLUS2

 

The runner up is the Icom ID-51 PLUS2 (Buy: US, UK). It’s more than 35% cheaper than the TH-D74 and it does everything but APRS. From this list it probably has the most bang for the buck since there are two ways of doing APRS: through D-Star repeaters that have it enabled or with an extra piece of kit that you plug to it. The audio quality seems not to be as good as the TH-D74 but it still is great. Like the TH-D74, this is a radio to buy, keep and don’t think about equipment for many years (at least not hand-helds).

Icom ID-51A PLUS2

After these two, we get into the get a radio now with the intention of upgrading later.

Icom IC-E91

Icom IC-E91The Icom IC-E91 cost less than half of the TH-D74 but I’m a bit puzzled by it. I cannot find a lot of reviews or information about it. It doesn’t seem to be a popular unit. It can do D-Star but to transmit GPS it requires an external GPS module that would put it close to the cost of an ID-51 PLUS2. When it comes to APRS, it’s the same story as for the other Icom on this list.

Yaesu FT-60

Yaesu FT-60The Yaesu FT-60 is a good solid radio. It cost about a sixth of the TH-D74 and it only ticks the VHF/UHF boxes on my requirements so this is definitely one to get started and upgrade later.

A Yaesu FT-411E was my first radio and I always had a soft spot for Yaesu, so it saddens me that they decided to make their own proprietary protocol for digital radio. This is why you don’t see any higher end Yaesu models, I don’t want to use nor support System Fusion. I really hope one day Yaesu will start producing equipment with D-Star, then I will consider again buying their higher end models.

A Baofeng

baofeng's messy product line in the uk

This would cost me the same as a pizza. It’s definitely in the buy something to get started and upgrade later. From a cost point of view, this is a no-brainier. I could just go ahead and buy one or two just for the lolz. I do have two issues with it:

The first is quality. Obviously I don’t expect high end quality, but I read some reports of horrible things. I don’t want to buy a paperweight.

The second issue is that I don’t know which one to get. Their line of products is a mess. In the UK they have a gazillion different models. They changed names three times (Pofang, Misuta). Their website is confusing and once I drill down on all the models, they seem to be all the same. If you look at their American presence, there they offer two radios with clear pros and cons, none of which are available in the UK.

Conclusion

Well, I don’t have one. I haven’t made a decision yet. I’d like to just buy a Baofeng now and upgrade later, but it sounds like I’m buying a problem. Getting the Yaesu seems a bit expensive for an upgrade-later path (but not too bad). Getting any of the high ends feel like throwing money for a toy instead of taking on a new hobby in a sensible manner.

Any word of advice?

Book Review: Foundation Licence Now by Alan Betts

9781872309804_9c3c0da200c92b4703ae40246d591184I wished someone handed me this book years ago, when I moved to the UK, because I would have gotten my foundation amateur radio licence much, much sooner if I knew how simple it was. I have a similarly leveled licence from Argentina (LU5ARC) and it was much harder to obtain.

I found the structure of the book a bit erratic. Some chapters are formatted much different than others. I didn’t find this to be a problem though, just surprising. The content is generally covered well and I think people with no knowledge of electronics or radio could read it and understand it all.

I guess you could say the proof is in the pudding and whether I’ll pass the test, but being that I already took ham radio courses and I’m an electronic technician, me passing the test is no proof of the quality and usefulness of this book.

★★★☆☆

Buy Foundation Licence Now in USA
Buy Foundation Licence Now in UK
Buy Foundation Licence Now in Canada

Book Review: Getting Started In Amateur Radio by Steve Nichols

36282097I’m not an expert but I’m also not a beginner to ham radio (I’m LU5ARC in Argentina and I’ll be working on getting my UK license next month) and this book opened my eyes to a lot of new cool things to do in the world of amateur radio. I marked a lot of things here to explore once I get my license.

This book even has a section on antennas that give you a good idea of the sizes and types of arenas you could use for different bands.

On the negative, this book has quite a few grammatical errors and typos, which I don’t mind, but it also contains quite a bit of jargon that is never explained. A bit I knew already because of my limited experience with radio, a bit I had to look it up.

★★★★☆

Buy Getting Started In Amateur Radio in USA
Buy Getting Started In Amateur Radio in the UK
Buy Getting Started In Amateur Radio in Canada

An important lesson in consumer protection (for small businesses owners)

I recently bought a desktop computer from Dell and by the time it arrived I was wondering if it was powerful enough, so, I took it for a spin and found out that my suspicious were correct. It was not powerful enough for my needs. We’ll, no big deal, all I had to do was give them a call to arrange for a return and a refund. Dell told me I had 14 days to return it.

When I started the process they asked me if I bought it as an individual or a business. Well, it was for business and it was paid by my business. I didn’t know it at that point, but that meant that the European Union laws for consumer protection didn’t apply.

The EU has a cool off period on online purchases of 14 days. Within those 14 days you can return an item without having a reason. This is for people, not companies. I was exempt of that protection and the terms of service of Dell is: no returns. I got so used to be able to return whatever I want, that this really surprised me. It was surreal.

Did you notice that Dell return policy is the absolute minimum that the EU requires? 14 days for consumers, no return for businesses. I thought most companies were accepting returns because keeping customers happy it’s good for business. Certainly some are, for example, Amazon never refused a return no matter whether it was a business or personal purchase.

This made me wonder: how many other companies look good because the EU is making them and not because they are good. What will happen when the UK leaves the EU? I bet many of these battles will have to be fought again, some will be lost, some will be won.

After a lot of whining and protesting, Dell accepted to take the computer back, but from now on I’ll think twice about buying things from Dell. Even when buying Dell products.

For example, for my new workstation I need a monitor and my research pointed me to one that Dell offers. If you I went to Dell’s web site, and clicked “For Work”, the monitor was 20% cheater than if I clicked “For Home”. Maybe that’s the cost of accepting returns, maybe it’s just dynamic pricing. Thankfully I found the monitor on Amazon, cheaper than the cheapest price Dell was charging, on prime, so delivery was even faster. I obviously ordered them on Amazon.

Picture by www.cafecredit.com

Book Review: Spring REST by Balaji Varanasi, Sudha Belida

9781484208243If you need to build a RESTful API with Java, this book is the way to go. Short and sweet, it covers most of what you need without too much faff.

I particularly liked the chapter on errors. It has quite a bit of code that I copied into my project as a starting point.

When it came to testing, I liked that it acknowledged the need to do integration testing, that is, testing the API with a real database backend. I personally don’t buy the mock everything custom of the Java world as bugs can hide in the integration and these days it’s so easy and fast to test against a real database that I don’t see any value in mocking it out (if you do, the book covers that too).

It has a small section on writing clients using RestTemplate which I wish it was bigger but I understand my needs in this regard are not that common. Particularly, there was no mention on how to deal with the validation errors scheme introduced earlier when using RestTemplate.

All in all, I like this book. For me, computer books should either be short or comprehensive (not padded) and this one is a good example of a good short to-the-point book.

★★★★☆

Buy Spring REST in USA
Buy Spring REST in UK
Buy Spring REST in Canada

Book Review: Beginning Hibernate by Jeff Linwood, Dave Minter

Begining HibernateSweet introduction to Hibernate. I can’t believe it doesn’t cover migrations (and I’m sure some people will point out migrations it’s not part of Hibernate, but without it, there’s no good way to maintain a production database).

The book is on the short side for a computer book and that’s a huge plus. Even then, if you are going to do Spring Boot, like I am, there’s quite a few sections of the book you can skip.

★★★☆☆

Buy Beginning Hibernate: For Hibernate 5 in USA
Buy Beginning Hibernate: For Hibernate 5 in United Kingdom
Buy Beginning Hibernate: For Hibernate 5 in Canada

Using Oracle’s JDK in CircleCI (with Gradle)

I’m evaluating re-writing Dashman in Java (instead of Electron). It’s too early to tell, but so far all the experiments and the early re-write are going well and it’s solving the issues I was having with Electron. This short post is about CircleCI.

Because now I’m using common, boring technologies, I decided setting a CI was going to be easy enough that I didn’t mind doing it and I chose CircleCI, mostly because of their free plan.

Sadly, my project didn’t work out of the box. JavaFX was nowhere to be found. The reason was that CircleCI uses OpenJDK instead of the Oracle’s JDK by default. I guess that’s enough for the vast majority of people. Switching to Oracle’s JDK was not hard, but I couldn’t find a straightforward post, so, this is it.

CircleCI gives you a configuration example that contains something like this:

version: 2
  jobs:
    build:
      docker:
        # specify the version you desire here
        - image: circleci/openjdk:8-jdk

I’m not very familiar with Docker and how CircleCI uses, all I know is that it’s a container system for, essentially, operating system images. CircleCI has a repo of Docker images and the one that include’s Oracle’s JDK is called circleci/jdk8. What comes after the colon in the config is the version of the Docker image (I think) which Docker calls tags and for this one, at the time of this writing, there was 0.1.1 but you can easily check the latest one here: https://hub.docker.com/r/circleci/jdk8/tags/

With that in mind, the config should now look like this:

version: 2
  jobs:
    build:
      docker:
        # specify the version you desire here
        - image: circleci/jdk8:0.1.1

And that’s it… well, unless you are using Gradle. That image doesn’t provide Gradle, so, you need to replace all the mentions of gradle with gradlew and use the wrapper that should be part of your repo. But before that will work, you need to make that file executable on the CircleCI server by calling chmod +x gradlew on it. The resulting config file for me looks like this:

# Java Gradle CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-java/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/jdk8:0.1.1

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/repo

    environment:
      # Customize the JVM maximum heap limit
      JVM_OPTS: -Xmx3200m
      TERM: dumb

    steps:
      - checkout
      - run: chmod +x gradlew

      # Download and cache dependencies
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "build.gradle" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run: ./gradlew dependencies

      - save_cache:
          paths:
            - ~/.m2
          key: v1-dependencies-{{ checksum "build.gradle" }}

      # run tests!
      - run: ./gradlew test

And that’s it, that worked.