Nov 212012
 

Today I was working again on the undocked TopComponent that inspired the post Hiding Tabs for Undocked TopComponents, this time adding a custom statusbar to it. And in the process I found a way of adding a banner to a NetBeans Platform application. There might be unexpected side effects with layout, but so far it looks good. 🙂 Here is what my sample application looks like, to explain what I mean by ‘banner’ (the green part in the screenshot).

Sample application with banner

Sample application with banner

Well, as far as I gather the idea is not brand new. I had a hint from a forum thread that helped to point me in the right direction. Toni mentions there that you can add components outside the control of the window system, but the blog post linked to there no longer exists…

I started by browsing through the GUI elements in debug mode. And I soon found out that by calling

((JRootPane) WindowManager.getDefault().getMainWindow().
        getComponents()[0]).getContentPane()

you can find the main panel that contains all the GUI elements. And this panel has a BorderLayout. So lets look at the different parts of the NetBeans IDE as contained in this window to illustrate.

NetBeans IDE showing layout areas

NetBeans IDE showing layout areas

I created a normal JPanel form (I called mine BannerPanel) and added the components that you see on the screenshot to it. Then I created an installer class for the module, and into the restored method I put the following code:

WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
    @Override
    public void run() {
        Frame mainWindow = WindowManager.getDefault().getMainWindow();
        Container contentPane = 
                ((JRootPane) mainWindow.getComponents()[0]).getContentPane();
        BannerPanel banner = new BannerPanel();
        contentPane.add(BorderLayout.NORTH, banner);
        ((BorderLayout) contentPane.getLayout()).
                invalidateLayout(contentPane);
        mainWindow.validate();
    }
});

Now you will notice that I am putting the panel into BorderLayout.NORTH, which according to the screenshot earlier is where the toolbar already is. What is in fact in that space is a container panel that keeps the space for the toolbar. So replacing it means that the panel actually starts at the same height as the toolbar. And this means that you need to leave some open space at the top of the panel that you design. See the screenshot below showing my very green form in the GUI designer.

Banner in GUI designer

Banner in GUI designer

One last gotcha. You have to specify a height for the form by re-sizing it with the GUI designer. Otherwise the form will end up being small enough to be hidden behind the toolbar.

And remember – this is a way to bypass the NetBeans Platform window system to add components around it. So if things go wrong, you will have to go on a quest to find a Swing guru… 🙂

Nov 162012
 

Today I set out to accomplish something that appeared to be quite simple. However, it took me quite a few hours and lots of reading to find a solution. I do hope that this will be useful to other developers!

I have been working a JPanel form with a lot of different components on it, including JTextFields, JDateChoosers and some custom Swing components. And today I wanted to exclude some of the controls from the tab order. The controls I wanted to exclude were enabled but set as not editable, to allow the user to copy the values as required.

The first thing I tried was setting the components as not focusable. However, that meant that I couldn’t select the text with the mouse pointer anymore. So back to the drawing board.

I moved on to reading about the FocusTraversalPolicy mechanism (which I have never used before). And after much trial and error, I found this very simple solution. Just extend the class LayoutFocusTraversalPolicy, overriding the accept method as required. Here is the newly created class:

public class ExclusionFocusTraversalPolicy 
        extends LayoutFocusTraversalPolicy {

    private ArrayList components = new ArrayList();

    public void addExcludedComponent(Component component) {
        components.add(component);
    }

    @Override
    protected boolean accept(Component aComponent) {
        if (components.contains(aComponent)) {
            return false;
        }
        return super.accept(aComponent);
    }
}

And then in the form after adding the components call:

ExclusionFocusTraversalPolicy policy = new ExclusionFocusTraversalPolicy();
// add all the desired components to the exclusion list
policy.addExcludedComponent(textField);
setFocusTraversalPolicy(policy);
setFocusTraversalPolicyProvider(true);

That is it. Now when tabbing through the form, all the components in the exclusion list are skipped!

Nov 142012
 

In our NetBeans Platform application, we have a TopComponent that needs to always be opened in an undocked and maximised state. When I manually undocked the window the first time though, I immediately noticed that the single tab that appears in the window just looks really silly.

So I set out to get the window to automatically undock as well as to remove that annoying tab.

In order to get the window to be opened as undocked, I needed to define a new separated mode to dock the window into. See section 3 of Geertjan’s Secrets of the NetBeans Window System post for more details about the mode. Note that the mode’s kind property needs to be editor for the whole thing to work.

I called my new mode floater, and the code that opens and maximises the window now looked like this:

Mode floater = WindowManager.getDefault().findMode("floater");
TopComponent tc = 
        WindowManager.getDefault().findTopComponent("test2TopComponent");
floater.dockInto(tc);
tc.open();
JFrame root = (JFrame) SwingUtilities.getRoot(tc);
root.setExtendedState(root.getExtendedState() | Frame.MAXIMIZED_BOTH);

But the pesky tab was of course still there, so I needed more information. And in my search I came across another of Geertjan’s articles – Farewell to Space Consuming Weird Tabs. I did, however, not want to remove all the tabs from the whole application, just that particular one. So after creating the class test.NoTabsTabDisplayerUI as Geertjan describes, I had to find the right spot to set the UIManager property. And as it turns out, I just had to set the property before opening the window, and reset it to its previous value after. So the code finally is:

Mode floater = WindowManager.getDefault().findMode("floater");
Object oldTabDisplayer = UIManager.get("EditorTabDisplayerUI");
UIManager.put("EditorTabDisplayerUI", "test.NoTabsTabDisplayerUI");
TopComponent tc = 
        WindowManager.getDefault().findTopComponent("test2TopComponent");
floater.dockInto(tc);
tc.open();
JFrame root = (JFrame) SwingUtilities.getRoot(tc);
root.setExtendedState(root.getExtendedState() | Frame.MAXIMIZED_BOTH);
UIManager.put("EditorTabDisplayerUI", oldTabDisplayer);