Monday, May 1, 2017

Adding an Exit Dialog to your NetBeans Platform based RCP

Over time numerous requests to add an Exit Dialog box accumulated in my list of requested enhancements. I have always thought about where to hook up such a Dialog and after reading through the NetBeans Wiki I realized the ModuleInstaller class is a good candidate (rather than using the LifeCycleManager).

The DevFaqModulesStartupActions is mentioning the closing() method of each ModuleInstaller of each module has VETO rights to prevent the application from exiting.

So adding an instance of a ModuleInstaller in one of your modules of your RCP as described in the above DevFaqModulesStartupActions Wiki entry and overriding the closing() method with code asking the user if it is OK to exit in a modal dialog. If not, return false and VETO the exit sequence. My code turned out to look like below:




Friday, April 28, 2017

Houston NetBeans Platform User Group created !

At the latest HJUG (Houston Java User Group) meeting on April 26th, 2017, we created a group on LinkedIn with the very narrow focus on supporting Houstonians working on Desktop applications based on the NetBeans Platform. Look on LinkedIn for the group :   Houston NetBeans Platform User Group.

For a list of screenshots of NetBeans Platform based application got to https://netbeans.org/features/platform/index.html

Thursday, April 27, 2017

Set InitalMainWindowSize and location of numerous TopComponents

The NetBeans Wiki about DevFaqInitalMainWindowSize already gives an initial hint of how to control the size of your TopComponent at startup.What was missing for me was: How to place 2 (or more) TopComponents (both being of type "editor") next to each other ?

I will show the answer to this in a test  RCP in painful detailed steps to avoid any misunderstandings.

Assume we have a NetBeans Platform application with name PreDefineSize having two modules with names module1 holding the LeftTopComponent and a module2 holding the RightTopComponent.


Performing a Clean and Build and run will give


Assume that we would like the application at startup with both TopComponents next to each other with about 75% to the Left and 25% of the horizontal space to the Right module. I.e. Something like:

How to achieve this ?


1) After you have resized and placed the 2 TopComponents as you want, Click the LEFT module tab (just to make it the last active) and then exit the application.
2) Go to  PreDefineSize/build/testuserdir/config/Windows2Local
3) Copy the WindowManager.wswmgr to the src directory of module1



 4) Go to PreDefineSize/build/testuserdir/config/Windows2Local/Modes
5) Copy the editor.wsmode to the src directory of module1 and rename to editorWsmode.xml
6) Copy the anonymousMode_1.wsmode to the src directory of module1 and rename to editorRightWsmode.xml
7) Go to PreDefineSize/build/testuserdir/config/Windows2Local/Modes/anonymousMode_1
8) Copy the RightTopComponent.wstcref to the src directory of module1

9) Modify the editorRightWsmode.xml file and the value of the "unique" attribute to editorRight


Note :  In line 8 you might see that the "number" attribute is controlling the order.

10) Create the XML layer file in module1 like below


11) From the tree above open the module1- Important Files - XML Layer .... Modes

12) Create a new folder called editorRight



13) Edit the layer.xml in the src directory of module1 file like below


14) Now do a Clean and Build and the application will start with the layout and size you decided in Step 1


Here is the entire test NetBeans project :   PreDefineSize NB Project ZIP

Thursday, March 23, 2017

Keep Aspect Ratio of a JFXPanel embedded in a NetBeans TopComponent when resizing

Following the strategies outlined in the book "JavaFX Rich Client Programming on the NetBeans Platform" by Gail and Paul Anderson (Amazon reference) I still had trouble keeping a circle a circle after users decide to resize the TopComponent.

The FX Scene is using a StackPanel and on top of that Panels for different drawings. The ScatterChart sits on top of the StackPanel and causing a circle to become oval when the user reduces the width or height of the TopComponent.

Challenge is show below :



And what really should happen when like above the user fx reduces the width, is:

Like with the Egg of Columbus the solution is quite simple. Though you have to remember that the controller is executing in the FX Thread and the TopComponent on the Swing Event Thread.

In the TopComponent containing the JFXPanel, add the following to the componentOpened() method:


The "controller" object is the class (as described in the book mentioned above) and is executing on the FX Thread. The method with the long name is doing nothing else than setting the Pref size of the StackPane and the ScatterChart in the controller class like:



If any of you have a better way - drop a comment. The above at least made it work for me.


Thursday, October 6, 2016

Porting my Nb 6.5 RCP app to Nb 8.2

Over the years I have tried to port my Nb 6.5 based  Platform application to an updated NetBeans version. It usually stopped with some major showstopper which was too hard to figure out on my own or which nobody in the great NetBeans community had heard of or could reproduce.This was the case trying Nb 6.7, 6.8, 6.9, 7.0 or 7.2. Over the years I took notes of problems other porters have had and kept those in a list as I knew I would use them one day.

NB 8.2 was released on Oct 3rd, 2016  and I did already work on the 8.2RC which was released about two weeks before. Below I will simply list the issues I run into and which solutions made them go away.

In short:  NB 8.2. was the one release causing minimum of porting needed and I succeeded with the port (42 modules) under a week of work. Some of this time was due to issues with 3rd party products like Derby. (10.12.1.1 had issues with numerous triggers on the same table, which I fixed together with Bryan see https://issues.apache.org/jira/browse/DERBY-6726)

Update (Nov 2016): This fix is now part of the latest Derby 10.13.1.1 release.

1) Upgrade local build to Ant 1.9.7

No big deal really. Nb 8.2 has Ant 1.9.7 build into the distro but I also did have build scripts who could build the system outside NetBeans in batch. Upgrade was done just to have the same version as NetBeans.

2) Upgrade all modules Implementation versions 

Use Project --> properties.  This was done to make sure no old update Center could trigger an update suggestion on the newly upgraded system.

3)  Find which dependencies from NetBeans were needed

This was the first bigger puzzle game. Major split of API's were done in 8.0, like the Lookup was now it its own library. Also splits between Swing and non-swing code were done, like Progress API and Progress API - Swing. The idea was to take out as much as possible and with try and error see what dependencies need each other.

The main one to remove was under "platform" : Swing Layout Extension integration as it is deprecated.Which had implications on numerous TopComponents.  From the suite's project properties I only needed 3. "ide", "nb" and "platform".




To reduce carrying too much not-to-be-used jar files around, below I list the modules in each of those 3 nodes which I excluded and which did not trigger dependency warnings when removing.

"ide":  Bugzilla, CSS Preprocessors, CVS Installer, Database, Database Drivers, Docker*, Git*, Hudson*, ini4j, Issue Tracking*, Java DB Database Support,  Lexer to NetBeans Bridge, Local*, Mercurial, Mylyn Support Utilities, Navigate to Test, org.eclipse*, Resource Bundle Syntax Coloring, Schema-to-Beans Library, Selenium*, Smack API, Subversion*, Team Commons, Versioning*, XML WSDL API

Note: The Database, Database Drivers and Java DB Database Support were removed as I have my own Derby setup.

"netbeans": Bugzilla-Exception Reporter Bridge, Exception Detector, IDE Branding, Update Centers, Upgrade, Welcome Screen.

Note: My app is using the update center code but the Update Centers module is not needed.

"platform": Compatibility APIs, Old Enumeration API, Swing Layout Extension integration, UI Gestures Collector Infradtructure, UI Handler Library,

Note: The first 3 are deprecated modules and having written code in Nb 6.5 did have some swing layout using the Swing Layout Extension integration. (more below about that)

4) Add dependencies to your modules were compile errors happen due to missing classes

a) JUnit 4:   Add JUnit 4 to your Unit Test Packages if not there, possibly also Hamcrest
b) org.openide.util.ImageUtilities: Moved to module org-openide-util-ui, i.e. add Utilities API to your module
c) Lookup API:  The lookup code has its own module, hence all your code using this need to depend on this
d) org.netbeans.api.progress.ProgressHandleFactory : You will need to include Progress API and often as well Progress API - Swing dependencies.
e) org.openide.util.Utilities, util.HelpCtx, util.actions.CallableSystemAction: Add Utilities API
f) Module using  <...>.lookup(XyzProject.class) :  Triggers a class file for

org.netbeans.api.project.Project error. Also here - add the Project API as dependency

5) "The type of DialogDescriptor is erroneous” - kind of error
  
      This one did confuse me for a while. Compilation in Java ok, but NetBeans rejected to compile this. It turned out that adding a dependency on the Utilities API did solve this problem. Nasty part here is that you have no way of knowing this. No info why this is happening. See http://forums.netbeans.org/viewtopic.php?t=66899 for more details.
   
     6) javax.crypto not found

     Proguard 5.2.1 trouble shoot page explains that you shall add  jce.jar


-libraryjars 'C:\Program Files\Java\jre6\lib\jce.jar'

     7) Non-Singleton TopComponents NPE's when exiting the application

     A few of my TopComponents are non-singleton and I had to remove the files xyzSettings.xml and xyzWstcref.xml and all references in the layer.xml as well as any action possible left in there. Though removing the layer.xml entirely was a bad idea. For now I left a nearly empty layer.xml like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
<folder name="Windows2">
</folder>
</filesystem>


      8)  VisualLibrary Widget Background default changed from white to gray
    
       Add in each module   this.setBackground(Color.white);   where this extends GraphScene. See http://forums.netbeans.org/viewtopic.php?t=66919 for more details and info
 

9) FileUtil.preventFileChooserSymlinkTraversal deprecated in JDK 8

Just remove the line using this. 

10) ProgressHandleFactory.createHandle deprecated

Just use ProgressHandle.createString()

11)  The module org.jdesktop.layout has been deprecated

 Use javax.swing.GroupLayout instead. If most of your code was generated in NetBeans, set to Design mode, select the "From xyzTopComponent" in the Navigator and then in the "Form xyzTopComponent - Properties" window there is a pulldown menu for the "Layout Generation Style" where you can select "Standard Java 6 code" - this will change all your code.

 

12)  DropDownButtonFactory needs small change in usage pattern

I have been using the DropDownButtonFactory as described in https://blogs.oracle.com/geertjan/entry/org_openide_awt_dropdownbuttonfactory1 and combined with ContextAware like in http://wiki.netbeans.org/DevFaqDropdownMenuAddToolbarEnabled

The dropdownbutton is now just showing the gray box until the ContextAware action is enabling it. To fix this the code only needed to insert the icon directly as in

The code used in Nb 6.5:
dropDownButton = DropDownButtonFactory.createDropDownButton(
new ImageIcon(
new BufferedImage(32, 32, BufferedImage.TYPE_BYTE_GRAY)),
popup);

dropDownButton.setIcon(icon);

Fix for 8.2:
dropDownButton = DropDownButtonFactory.createDropDownButton(
icon,
popup);

i.e. do not call the .setIcon() method on the JButton.  


13)  JVM arguments -J-XX:PermSize are not needed in JDK 8 anymore

14)  Numerous of new NetBeans IDE specific menu points to be removed

Use the IDE via the "Important Files" -- XML layer --  this layer in context    to accomplish most of this task. (looove this tool !)

15) Java 8 source level gives "RELEASE_7" warnings.

Currently I simply ignore this. No idea what is happening, something with the Annotation system.

16) Compatibility injections

Got warnings like 

warning: had to upgrade dependencies for module com.effi.vin.model: added = [module org.netbeans.api.progress.compat8 > 1.40, module org.openide.filesystems.nb, module org.openide.filesystems.compat8] removed = []; details: [Separation of desktop and cleanup, Swing dependencies split away]

Not sure what they do but it looks like it works so far. Looks like the system is so smart to make sure the new module splits applied inject in runtime jars usually needed for binary backwards compatibility. Though I could not find code in my module using older code.  Anyone out there who can explain if this just simply happens to all modules or what I can look for triggering this ?


Update (Dec, 2016): After removing all warnings in NetBeans and adding new library dependencies, the compiler still said MyModule: added = [module org.openide.filesystems.compat8] removed = []; details: [Separation of desktop and cleanup] - even though there were no deprecated or older function calls left. FIX: For this I removed the dependency on "File System API" and added it again. - Voila, compiler warning gone, no more injections of the compat8.jar.


17) Branding update

Since Nb 6.9 (? or 7.0) you have to add "--branding  your_branding_token" into the myapp.conf file to make sure your splash, about screen, icons etc are picked up.

18) org.openide.filesystems.Repository.getDefault().getDefaultFileSystem()  deprecated

Replace with FileUtil.getConfigRoot()

19)  Remove default UpdateCenters made available to the user

LOL, after having build my app it suddenly informed me that the FileSystem module needs to be updated. For sure I had not this in my UpdateCenter. It turns out that 3 update centers are enabled by default and need to be hidden when you only want your users to get updates for your app via your UpdateCenter and to make sure that the NetBeans under the hood is not updated and causing non-tested possible problems with your deployed app.

Like in point 14) you can remove those via the  Important Files- XML Layer - this layer in context - Services - AutoupdateType.  In there, delete the "certified update provider", "distribution update provider" and the "pluginportal update provider" - in case you do not want to give users access to update from those straight into your RCP app.

20Refactor from SaveCookie to the Savable

Inspired by Geertjan's link (Geertjan bye SaveCookie)  you remove your dummy Node created to enable the SaveCookie and create your Savable. Now, in my situation the class triggering a Save is a non-TopComponent and hence a little differnt. But in general what you need to do is:
a) Remove the "Save" action via the Important Files - XML Layer -  this layer in context - Toolbars - File, but keep the SaveAll Icon
b) In the class controlling if anything needs saving add
    private InstanceContent content = new InstanceContent();
    private final Lookup myLookup = new AbstractLookup(content);
 

c) Now create like Geertjan is showing a private class MySavable and in the handleSave() you do
    content.remove();
    unregister();

d) The controlling class activates the SaveAll icon by adding a MySavable extends AbstractSavable to the lookup vis something like
        if (myLookup.lookup(MySavable.class) == null) {
            content.add(new MySavable(this));
        }
 


e) Now, other classes might see if there is some Savable and the current best way I found was using code like:
  Collection objCol = Savable.REGISTRY.lookupAll(Savable.class);

and simply check if the Collection is empty or not.  

 

That was it really. Not so bad, thinking the time period from 6.5 to 8.2.