dustinkredmond / FXTrayIcon

Tray Icon implementation for JavaFX applications. Say goodbye to using AWT's SystemTray icon, instead use a JavaFX Tray Icon.
MIT License
327 stars 26 forks source link

Updated library to handle passed image objects properly and entirely #47

Closed EasyG0ing1 closed 2 years ago

EasyG0ing1 commented 2 years ago

The setGraphic(File) method when used with Java 18, throws an exception, because the method was first loading the file into a JavaFX Image object by passing the files .gatAbsolutePath property, and when passing a path String into JavaFX Image(path), if the path is not preceeded with file:, it throws an Exception. I don't know if this is true with older versions of Java or not, but I assume not since no one mentioned the error previously.

As I thought about a solutionm to the problem, and studied the code, I realized something that I feel is rather important: FXTrayIcon initially required images to be passed in via a URL into the class constructors. But as the library has evolved, the needs of different developers necessitated some changes that added more options for the icon file itself and how it is passed into the library, and those additions were offred in the setGraphic methods.

It didn't make a lot of sense to me, to pass in a File object with the setGraphic method, then convert that File into a JavaFX Image, then use SwingFXUtilities to convert it into the required AWT Image object. So I wrote a loadImageFromFile method that simply takes the file and loads it directly into an AWT Image via FileStream.

This solved my problem.

But then, after looking things over, it also occured to me that it would be best to offer developers different options for passing in the image that becomes the icon for FXTI.

So, I created some overloaded loadImageFromFile private methods that handle different scenarios. But there is one more consideration required when rendering the final icon image in the tray and that is the size of the image needs to be different depending on which operating system is running the library.

Since FXTrayIcon currently has TWO methods that allow a developer to pass in an icon image that can have any dimension at all without those dimensions being specified, I felt that it would be best to only allow TWO options for passing in an image object.

1) Pass the object into FXTrayIcon without any dimensions, at which point, the library will set the dimensions of the image before using it.

2) Pass the image object into FXTrayIcon with the specified dimensions along with it.

SO, I CONSOLIDATED the various options for image objects that are currently accepted by the library, but in different scenarios, and I made all of those options available under all scenarios. Here are the scenarios:

Under the setGraphic method, these objects are accepted:

During FXTrayIcon class instantiation, these objects are accepted:

The Builder class follows the class constructors.

With these changes in this PR, I have consolidated all of the accepted objects so that they can all be used whether at instantiation or during runtime. I added the safety measure where when an object is passed into the library without any dimensions specified, the dimensions get assigned based on the OS. And if the object is passed into the library with dimensions, then the dimensions passed as argument get used.

So with this PR, the following image objects can now be used by a developer both at instantiation as well as during runtime if desired:

The use of SwingFXUtils is only employed when a JavaFX Image object is passed into the library. All other objects use the AWT method of creating an Image object which can accept URL or InputStream and in the case of a File object, the object is first assigned to an InputStream then the AWT Image is created from that.

Javadoc comments have all been properly assigned to the relevant portions of the library.

Backward compatibility has been completely maintained. An upgrade to this version of the libary will not affect any code that uses the current version of the library.

All changes have been tested - each and every one, and everything works flawlessly.

EasyG0ing1 commented 2 years ago

@dustinkredmond

Not sure what my logic was when I first started working on this.

The setGraphic method, If I remember correctly, was originally consistent with the class constructors, which only took the graphic in as a URL. Nothing wrong with that, it keeps things simple and simple - WORKS! Your code was tight and dialed in, but then people submitted PRs to add capability and you were overloaded at work and buying a house and I think it just sort of evolved to where it is now. But having the options like this is going to be nice, especially for people like me who wrestle with objects like URLs for some reason ... File objects are things that you don't have to put much thought into - perfect for 'cave man' coding styles ☺

EasyG0ing1 commented 2 years ago

@dustinkredmond - I modified the branch:

While I was working with the updated library in one of my applications using Java 18, I noticed that no matter what I did, the default exit menu would not close out the application, and I think it has to do with removing the dock icon from the application at run time where simply issuing a Platform.exit() would not close the program, so I added some code to handle that in situations when FXTray Icon is being run by a Mac.

Also, I noticed some other quirkiness when using the Builder class where items were not being added in the order in which they are included in the build sentence ...

Also, when a developer invokes the default exit menu item, but then, later on, adds a Menu or a MenuItem after the trayIcon is shown, there was no mechanism in place to ensure that the exit menu remained at the bottom of the menu list.

SO - I added code that ensures that the default exit menu always stays at the bottom of the list. I also added the ability for the developer to override the default action on the exit menuItem so that they can invoke any code they want when that menuItem is clicked ... and it will always remain at the bottom of the menu list.

And in order to get all of this working with the Builder class, it became necessary to add a package-private class and enum, that I called BuildOrderUtil (I had to add the Util part to get it to pass the Travis UI code check in here), which the Builder class uses as items are added in the build sentence, then it utilizes that class to add the items in order, once the trayIcon is instantiated.

EasyG0ing1 commented 2 years ago

@dwalluck - I had accepted IntelliJ's spelling corrections without scrutinizing them. They are fixed now.

dustinkredmond commented 2 years ago

Thanks to the both of you. Merging this to main, hoping to push a release this weekend.