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

Provide an indirect path to the TrayIcon object #74

Closed EasyG0ing1 closed 1 year ago

EasyG0ing1 commented 1 year ago

Concerning Issue #72 - I spent some time working with the FXTrayIcon class in an extended subclass to see about using the protected method getTrayIcon() and though it can be relatively easy to do when using the base class constructors, it becomes more of a challenge when trying to also use the extended Builder class. Also, having to create a subclass just to gain access to that object seems to me to be a bit inconvenient, though I certainly can understand and appreciate the intent behind declaring that object as protected ... this is a JavaFX library and so all efforts should indeed be made to present it as a full JavaFX library.

So what I came up with will both maintain the existing protection of the object where its not possible to reference it via the protected method AND ALSO provide a relatively convenient way of getting to the object while it remains not exposed directly.

I created a class called Restricted that is only local to the package that it's in (so it cannot be accessed nor even seen while using the library), then I put the awt TrayIcon object in that class declaring it as final so that it is only created one time and that is when the final FXTrayIcon class constructor is called and it instantiates the Restricted class ... but there's a twist...

The variable named restricted is defined as being of type RestrictedInterface but when the Restricted class is instantiated in the final constructor, it is instantiated and assigned to that variable.

Because the Restricted class is only accessible to the package it exists in, the only way to make its getTrayIcon public method accessible outside of the package is by having that class implement the interface which has the declaration of that method declared as public - Restricted Overrides the interface method.

The result of this is that users of the library can use the getTrayIcon method that's inside the package-private Restricted class without being able to see or access Restricted directly, which preserves the goal of keeping that object protected.

Once FXTrayIcon is instantiated, a developer can gain access to TrayIcon like this:

fxtrayIcon.getRestricted().getTrayIcon();

It should be noted that the RestrictedInterface class is public and therefore it can be seen by users of the library, but there is no code in that class for anyone to use so its exposure poses no threat to any part of anything within the scope of the library.

Here is what this accomplishes: 1) The TrayIcon object remains protected and not DIRECTLY accessible from the instantiated FXTrayIcon class as you originally intended. 2) The class that holds the TrayIcon object cannot be seen by a developer. 3) The TrayIcon object is guaranteed to only be created ONE TIME through the final class constructor of FXTrayIcon.

I believe this is a solution that meets both needs - protecting the object while making it accessible but never "accidentally" accessible ... the dev will have to want to get at it and also know how to do it.

The original behavior of FXTrayIcon has not changed at all so this PR will have no negative impact on existing users.

Java doc comments were added everywhere new code was added.

README was updated to explain the added functionality.

This has been tested and it works.

EasyG0ing1 commented 1 year ago

I also added one other method to the main class but that one just lets people add MenuItems withing needing to first create a menuItem object ... its similar to what the Builder class offers, only it offers it post instantiation.

EasyG0ing1 commented 1 year ago

@dustinkredmond I also fixed a bug per issue #71 making sure that the insertion index will never go negative.

Actually, I decided to change that and not make sure that the index being pushed into the stack never goes negative ... the index being pushed into should always be whatever the current count is of the stack. So if there are no items in it, then the right index to insert into is 0. If there are 1 items in there, then that item will exist at index 0 so the correct index to push into would be index 1 etc.