JDK-4801152 : Various Focus problems with JInternalFrame
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.1
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 2003-01-09
  • Updated: 2005-04-15
  • Resolved: 2005-04-15
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
 JTreeModel and do the same
  * thing in getChildCount().  Or, if you aren't using TreeNode you could
  * write your own TreeModel implementation.
  * Another solution would be to listen for TreeNodeExpansion events and
  * the first time a node has been expanded post the appropriate insertion
  * events.  I would not recommend this approach though, the other two
  * are much simpler and cleaner (and are faster from the perspective of
  * how tree deals with it).
  *
  * NOTE: getAllowsChildren() can be messaged before getChildCount().
  *       For this example the nodes always allow children, so it isn't
  *       a problem, but if you do support true leaf nodes you may want
  *       to check for loading in getAllowsChildren too.
  *
  * @version 1.9 06/13/02
  * @author Scott Violet
  */

public class DynamicTreeNode extends DefaultMutableTreeNode
{
//    // Class stuff.
    /** Number of names. */
    static protected float                    nameCount;

    /** Names to use for children. */
    static protected String[]                 names;

    /** Used to generate the names. */
    static protected Random                   nameGen;

    /** Number of children to create for each node. */
    static protected final int                DefaultChildrenCount = 7;

    static {
        {
	    names = new String[] {"Mark Andrews", "Tom Ball", "Alan Chung",
				      "Rob Davis", "Jeff Dinkins",
				      "Amy Fowler", "James Gosling",
				      "David Karlton", "Dave Kloba",
				      "Dave Moore", "Hans Muller",
				      "Rick Levenson", "Tim Prinzing",
				      "Chester Rose", "Ray Ryan",
				      "Georges Saab", "Scott Violet",
				      "Kathy Walrath", "Arnaud Weber" };
	}
	nameCount = (float)names.length;
	nameGen = new Random(System.currentTimeMillis());
    }


    /** Have the children of this node been loaded yet? */
    protected boolean           hasLoaded;

    /**
      * Constructs a new DynamicTreeNode instance with o as the user
      * object.
      */
    public DynamicTreeNode(Object o) {
	super(o);
    }

    public boolean isLeaf() {
	return false;
    }

    /**
      * If hasLoaded is false, meaning the children have not yet been
      * loaded, loadChildren is messaged and super is messaged for
      * the return value.
      */
    public int getChildCount() {
	if(!hasLoaded) {
	    loadChildren();
	}
	return super.getChildCount();
    }

    /**
      * Messaged the first time getChildCount is messaged.  Creates
      * children with random names from names.
      */
    protected void loadChildren() {
	DynamicTreeNode             newNode;
	int                         randomIndex;

	for(int counter = 0; counter < DynamicTreeNode.DefaultChildrenCount;
	    counter++) {
	    randomIndex = (int)(nameGen.nextFloat() * nameCount);
	    newNode = new DynamicTreeNode(names[randomIndex]);
	    /* Don't use add() here, add calls insert(newNode, getChildCount())
	       so if you want to use add, just be sure to set hasLoaded = true
	       first. */
	    insert(newNode, counter);
	}
	/* This node has now been loaded, mark it so. */
	hasLoaded = true;
    }
}



---------- END SOURCE ----------
(Review ID: 178832) 
======================================================================


Name: jk109818			Date: 01/09/2003


FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Internal frames bugs:
  A. The initial focus value is lost
  B. The focus is lost when minimizing or closing an
internal frame
  C. The "Alt-T" does not work when minimizing or closing
an internal frame


REGRESSION.  Last worked in version 1.4.1

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
A. The initial focus value is lost
1.  Open a frame "New Tree/attributes".
2.  Go to the field "show root".
3.  Open anoter frame
4.  Go back to the previous frame
      -> the focus is set back to the tree-field

B. The focus is lost when iconify or closing an internal
frame
1. Open a frame "New Tree attributes" or "NewSpilt
Tree/attributes"
2. Open a frame "New Tree attributes" or "NewSpilt
Tree/attributes"
3. Switch one frame to another and select a component.
4. Iconify or closing one frame.
     There is no focus anymore in the other frame.
Even "Alt-T" does not work.

C. The "Alt-T" does not work when minimizing or closing an
internal frame
1.  Open a frame "New Tree attributes" or "NewSplit
Tree/attributes".
2.  Minimize the frame
3.  Press  "Alt-T" to open the menu "Tree"
    --> Does not work



EXPECTED VERSUS ACTUAL BEHAVIOR :
A. The initial focus value is lost
     The expected result is that the focus will be on the
field where you left latest.

B. The focus is lost when minimizing or closing an internal
frame
     The expected result is that the focus will be on the
field where you left latest.
 
C. The "Alt-T" does not work when minimizing or closing an
internal frame
  The menu "Tree" must be opened.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
//The code is taken from the demo version of JDK 1.4 "SampleTree"

//SampleTee.java
/*
 * Copyright (c) 2002 Sun Microsystems, Inc. All  Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduct the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
 * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
 * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
 * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that Software is not designed, licensed or intended for
 * use in the design, construction, operation or maintenance of any nuclear
 * facility.
 */

 /*
  * Changes made, to generate some bugs
  * The Tree is now under MyInternalFrame
  */

/*
 * @(#)SampleTree.java	1.21 02/06/13
 */

import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.DefaultDesktopManager;
import java.awt.Container;

import javax.swing.*;
import javax.swing.event.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.*;
import javax.swing.tree.*;

/**
  * A demo for illustrating how to do different things with JTree.
  * The data that this displays is rather boring, that is each node will
  * have 7 children that have random names ...
  *
  * @version 1.21 06/13/02
  * @author Scott Violet
  */

public class SampleTree
{
    protected JFrame            frame;
    private JDesktopPane  desktop = new JDesktopPane(); //a specialized layered
pane

    /**
      * Constructs a new instance of SampleTree.
      */

    public SampleTree() {
	// Force SampleTree to come up in the Cross Platform L&F
	try {
	    UIManager.setLookAndFeel
(UIManager.getCrossPlatformLookAndFeelClassName());
	    // If you want the System L&F instead, comment out the above line
and
	    // uncomment the following:
	    // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName
());
	} catch (Exception exc) {
	    System.err.println("Error loading L&F: " + exc);
	}


	JMenuBar         menuBar = constructMenuBar();


	frame = new JFrame("SampleTree");
	frame.setJMenuBar(menuBar);
	frame.setBackground(Color.lightGray);

        desktop.setDesktopManager(new DefaultDesktopManager());
        setContentPane(frame, desktop);

	frame.addWindowListener( new WindowAdapter() {
	    public void windowClosing(WindowEvent e) {System.exit(0);}});

//	frame.pack();
//        this.createFrame();
        frame.setSize(500, 500);
	frame.show();
    }

    /** Construct a menu. */
    private JMenuBar constructMenuBar() {
	JMenu            menu;
	JMenuBar         menuBar = new JMenuBar();
	JMenuItem        menuItem;

	/* Good ol exit. */
	menu = new JMenu("File");
	menuBar.add(menu);

	menuItem = menu.add(new JMenuItem("Exit"));
	menuItem.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
		System.exit(0);
	    }});

	menu = new JMenu("Tree");
        menu.setMnemonic('T');
	menuBar.add(menu);

	menuItem = menu.add(new JMenuItem("New Tree"));
	menuItem.addActionListener(new NewOnlyTreeAction());
	menuItem = menu.add(new JMenuItem("New Tree attributes"));
	menuItem.addActionListener(new NewAction());
	menuItem = menu.add(new JMenuItem("NewSpilt Tree/attributes"));
	menuItem.addActionListener(new NewSplitAction());

	return menuBar;
    }

    class NewOnlyTreeAction extends Object implements ActionListener
    {
	public void actionPerformed(ActionEvent e)
        {
          SampleTree.this.createFrame(true, false);
        }
    }

    class NewAction extends Object implements ActionListener
    {
	public void actionPerformed(ActionEvent e)
        {
          SampleTree.this.createFrame(false, false);
        }
    }

    class NewSplitAction extends Object implements ActionListener
    {
	public void actionPerformed(ActionEvent e)
        {
          SampleTree.this.createFrame(false, true);
        }
    }

    static public void main(String args[]) {
      new SampleTree();
    }

    private void setContentPane(JFrame  frame, Container contentPane) {
        frame.getRootPane().setContentPane(contentPane);
    }

    private void createFrame(boolean onlyTree,
                             boolean  split) {
        MyInternalFrame frame = new MyInternalFrame(onlyTree, split);
	frame.setVisible(true); //necessary as of 1.3; OK to use before
        desktop.add(frame);
        try {
            frame.setSelected(true);
        } catch (java.beans.PropertyVetoException e) {}
    }
}


//MyInternalFrame.java
/**
 * Created for generating testing purposes
 * Most of the code is taken fram SampleTree
 */

import java.awt.event.*;
import java.awt.*;
import java.beans.PropertyVetoException;
import javax.swing.*;
import javax.swing.event.*;

import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.DefaultDesktopManager;
import java.awt.Container;

import java.util.*;
import javax.swing.tree.*;

public class MyInternalFrame extends JInternalFrame
{
  static int openFrameCount = 0;
  static final int xOffset = 30, yOffset = 30;
  /* Create the tree. */
  protected JTree             tree;
  /** Tree model. */
  protected DefaultTreeModel        treeModel;

  public MyInternalFrame(boolean onlyTree,
                         boolean split)
  {
    super("Document #" + (++openFrameCount),
          true, //resizable
          true, //closable
          true, //maximizable
          true);//iconifiable

    //...Create the GUI and put it in the window...

    //...Then set the window size or call pack...
    setSize(300,300);

    //Set the window's location.
    setLocation(xOffset*(openFrameCount % 8), yOffset*(openFrameCount%8));
    try
    {
      jbInit(onlyTree, split);
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private void jbInit(boolean  onlyTree,
                      boolean  split) throws Exception
  {
    /* Create the JTreeModel. */
    DefaultMutableTreeNode root = createNewNode("Root");
    treeModel = new DefaultTreeModel(root);

    /* Create the tree. */
    tree = new JTree(treeModel);

    /* Enable tool tips for the tree, without this tool tips will not
       be picked up. */
    ToolTipManager.sharedInstance().registerComponent(tree);

    /* Make the tree use an instance of SampleTreeCellRenderer for
       drawing. */

    /* Make tree ask for the height of each row. */
    tree.setRowHeight(-1);

    Container  cont = this.getContentPane();
    cont.setLayout(new BorderLayout());

    JScrollPane        sp = new JScrollPane();
    sp.setPreferredSize(new Dimension(300, 300));
    sp.getViewport().add(tree);
    if (onlyTree)
    {
      cont.add("Center", sp);
    }
    else if (split)
    {
      /* Put the Tree in a scroller. */
      JSplitPane  splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
      cont.add(splitPane, BorderLayout.CENTER);

      splitPane.setContinuousLayout(true);
      splitPane.setDividerSize(3);
      cont.add(splitPane, BorderLayout.CENTER);

      splitPane.add(sp, JSplitPane.TOP);
      splitPane.setDividerLocation(200);
      splitPane.add(constructOptionsPanel(), JSplitPane.BOTTOM);
    }
    else
    {
      cont.add("Center", sp);
      cont.add("South", constructOptionsPanel());
    }
  }

    /** Constructs a JPanel containing check boxes for the different
      * options that tree supports. */
    private JPanel constructOptionsPanel() {
	JCheckBox               aCheckbox;
	JPanel           retPanel = new JPanel(false);
	JPanel           borderPane = new JPanel(false);

	borderPane.setLayout(new BorderLayout());
	retPanel.setLayout(new FlowLayout());

	aCheckbox = new JCheckBox("show handles");
	aCheckbox.setSelected(tree.getShowsRootHandles());
	aCheckbox.addChangeListener(new ShowHandlesChangeListener());
	retPanel.add(aCheckbox);

	aCheckbox = new JCheckBox("show root");
	aCheckbox.setSelected(tree.isRootVisible());
	aCheckbox.addChangeListener(new ShowRootChangeListener());
	retPanel.add(aCheckbox);

	borderPane.add(retPanel, BorderLayout.CENTER);
	return borderPane;
    }


    /**
      * ShowHandlesChangeListener implements the ChangeListener interface
      * to toggle the state of showing the handles in the tree.
      */
    class ShowHandlesChangeListener extends Object implements ChangeListener
    {
	public void stateChanged(ChangeEvent e) {
	    tree.setShowsRootHandles(((JCheckBox)e.getSource()).isSelected());
	}

    } // End of class SampleTree.ShowHandlesChangeListener

    /**
      * ShowRootChangeListener implements the ChangeListener interface
      * to toggle the state of showing the root node in the tree.
      */
    class ShowRootChangeListener extends Object implements ChangeListener
    {
	public void stateChanged(ChangeEvent e) {
	    tree.setRootVisible(((JCheckBox)e.getSource()).isSelected());
	}

    } // End of class SampleTree.ShowRootChangeListener


    protected DefaultMutableTreeNode createNewNode(String name) {
      return new DynamicTreeNode(name);
    }
}


//DynamicTree.java

/*
 * Copyright (c) 2002 Sun Microsystems, Inc. All  Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduct the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
 * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
 * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
 * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that Software is not designed, licensed or intended for
 * use in the design, construction, operation or maintenance of any nuclear
 * facility.
 */

/*
 * @(#)DynamicTreeNode.java	1.9 02/06/13
 */

import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.util.Random;

/**
  * DynamicTreeNode illustrates one of the possible ways in which dynamic
  * loading can be used in tree.  The basic premise behind this is that
  * getChildCount() will be messaged from JTreeModel before any children
  * are asked for.  So, the first time getChildCount() is issued the
  * children are loaded.<p>
  * It should be noted that isLeaf will also be messaged from the model.
  * The default behavior of TreeNode is to message getChildCount to
  * determine this. As such, isLeaf is subclassed to always return false.<p>
  * There are others ways this could be accomplished as well.  Instead of
  * subclassing TreeNode you could subclass

Comments
EVALUATION There are already a number of bugs opened regarding the focus problems of internal frames. These will be fixed in the next major release. ###@###.### 2003-01-22 Each of these issues is being tracked under various other bug ids. You may want to keep track of these other bug ids for further updates. ###@###.### 2004-09-03 Behaviors B and C are not reproducible in 1.6.0-ea-b32. Behavior A is a duplicate of 4302764 focus is not set in JInternalFrame Closing as duplicate of 4302764. ###@###.### 2005-04-15 23:17:58 GMT
15-04-2005