JToolBar IllegalArgumentException when dropped back into GridBagLayout

gridbaglayout, illegalargumentexception, java, layout-manager, swing

Solution

That's snippet from BasicToolBarUI source

    public void windowClosing(WindowEvent w) {
        if (toolBar.isFloatable()) {
            if (dragWindow != null)
                dragWindow.setVisible(false);
            floating = false;
            if (floatingToolBar == null)
                floatingToolBar = createFloatingWindow(toolBar);
            if (floatingToolBar instanceof Window) ((Window)floatingToolBar).setVisible(false);
            floatingToolBar.getContentPane().remove(toolBar);
            String constraint = constraintBeforeFloating;
            if (toolBar.getOrientation() == JToolBar.HORIZONTAL) {
                if (constraint == "West" || constraint == "East") {
                    constraint = "North";
                }
            } else {
                if (constraint == "North" || constraint == "South") {
                    constraint = "West";
                }
            }
            if (dockingSource == null)
                dockingSource = toolBar.getParent();
            if (propertyListener != null)
                UIManager.removePropertyChangeListener(propertyListener);
            dockingSource.add(toolBar, constraint);

As you can see it tries to pass constraintBeforeFloating String as constraint but GridBagLayout expects GridBagConstraints.

constraintBeforeFloating = calculateConstraint();

and

private String calculateConstraint() {
    String constraint = null;
    LayoutManager lm = dockingSource.getLayout();
    if (lm instanceof BorderLayout) {
        constraint = (String)((BorderLayout)lm).getConstraints(toolBar);
    }
    return (constraint != null) ? constraint : constraintBeforeFloating;
}

So when floating is closed UI tries to pass curretn constraint (String) to GridBagLayout and fails.

Problem

Why does this code throw an `IllegalArgumentException` when the tool bar is dragged off the GUI, then closed (to return it to the GUI)? I could understand why it might be improper to add a component with no constraint, but in this case, the initial addition of the toolbar to the panel (which uses `GridBagLayout`) without a constraint causes no such problem. Why should it occur the 2nd and subsequent times it is added? The code is adapted from this answer, but both codes show the same problem. Code ``` import java.awt.*; import javax.swing.*; public class GridBagToolBarOddity { public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { JPanel gui = new JPanel(new GridBagLayout()); JToolBar tb = new JToolBar(); tb.add(new JLabel("Drag me off, then drop me back!")); gui.add(tb); gui.setPreferredSize(new Dimension(300, 100)); gui.setBackground(Color.RED); JFrame f = new JFrame("Demo"); f.add(gui); f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); f.setLocationByPlatform(true); f.pack(); f.setVisible(true); } }; SwingUtilities.invokeLater(r); } } ``` Exception ``` Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: cannot add to layout: constraints must be a GridBagConstraint at java.awt.GridBagLayout.addLayoutComponent(GridBagLayout.java:702) at java.awt.Container.addImpl(Container.java:1120) at java.awt.Container.add(Container.java:966) at javax.swing.plaf.basic.BasicToolBarUI$FrameListener.windowClosing(BasicToolBarUI.java:1265) at java.awt.Window.processWindowEvent(Window.java:2051) at javax.swing.JDialog.processWindowEvent(JDialog.java:681) at java.awt.Window.processEvent(Window.java:2009) at java.awt.Component.dispatchEventImpl(Component.java:4861) at java.awt.Container.dispatchEventImpl(Container.java:2287) at java.awt.Window.dispatchEventImpl(Window.java:2719) at java.awt.Component.dispatchEvent(Component.java:4687) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735) at java.awt.EventQueue.access$200(EventQueue.java:103) at java.awt.EventQueue$3.run(EventQueue.java:694) at java.awt.EventQueue$3.run(EventQueue.java:692) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87) at java.awt.EventQueue$4.run(EventQueue.java:708) at java.awt.EventQueue$4.run(EventQueue.java:706) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:705) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.run(EventDispatchThread.java:91) ```

Original source