JDK-4374402 : Mnemonics Orientation is broken in RTL and Bidi enabled JMenu and JMenuItem
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.0,1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic,windows_2000
  • CPU: x86
  • Submitted: 2000-09-27
  • Updated: 2005-08-12
  • Resolved: 2005-08-12
Related Reports
Duplicate :  
Description
Name: jbT81659			Date: 09/27/2000

OS: Win98-Arabic/Hebrew
JDK:1.4.0-Beta32

This bug applies to other Swing components like JButton, JCheckBox....
For RTL Text. The Mnemonic underscore is not displayed under the correct character 
in RTL and bidi text. The Mnemonics underscore  is displayed under the last 
character of the word (Farthest left) instead of the first 
character (Farthest right).

To reproduce bug:
1- Compile and run the following code
2- Do "alt+g". Note that English Menu opened
3- Note that the Mnemonics for each JMenuItem is displayed correctly under the first character
4- Try to use the corresponding Arabic or Hebrew Mnemonics for the other JMenus
5- Note that there is no rsponse

--------Code-----------

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class mnemonics extends JApplet 
{
    public void init()
    {
        JFrame frame = new JFrame("\u0645\u062b\u0627\u0644");
        frame.setJMenuBar(new jMenuX());
        frame.setSize(500, 400);
        frame.setVisible(true);
    }
    public static void main(String[] argv)
    {
        jMenuX example = new jMenuX();
        example.pane = new JTextPane();
        example.pane.setPreferredSize(new Dimension(250, 300));
        example.pane.setBorder(new BevelBorder(BevelBorder.LOWERED));
        JFrame frame = new JFrame("\u0645\u062b\u0627\u0644");
        frame.getContentPane().add(example, BorderLayout.NORTH);
        frame.getContentPane().add(example.pane, BorderLayout.SOUTH);
        frame.setFont(new Font("Lucida Sans Regular", Font.PLAIN,8));
        frame.setSize(500, 400);
        frame.setVisible(true);
        frame.addWindowListener( new WindowAdapter()
        {
           public void windowClosing( WindowEvent e)
           {
              System.exit(0);
           }
        });
     }
}
class jMenuX extends JMenuBar implements ActionListener 
{
      public JTextPane pane;

   String[] fileItemsEnglish = new String[] 
   {    
       "\u0041\u0042\u0043\u0044", 
       "\u0061\u0062\u0063\u0064", 
       "\u0065\u0066\u0067\u0068", 
       "\u0030\u0031\u0032\u0033" 
   };


   String[] fileItemsArabic = new String[] 
   {    
       "\u062c\u062f\u064a\u062f", 
       "\u0641\u062a\u062d", 
       "\u062d\u0641\u0638", 
       "\u062e\u0631\u0648\u062c" 
   };


   String[] fileItemsHebrew = new String[] 
   {    
       "\u05d7\u05d3\u05e9", 
       "\u05e4\u05ea\u05d9\u05d7\u05d4", 
       "\u05e9\u05de\u05d9\u05e8\u05d4", 
       "\u05d9\u05e6\u05d9\u05d0\u05d4" 
   };

   String[] fileItemsBidi = new String[] 
   {    
       "\u062c\u062f\u064a\u062f\u0020\u05d7\u05d3\u05e9", 
       "\u0641\u062a\u062d\u0020\u05e4\u05ea\u05d9\u05d7\u05d4", 
       "\u062d\u0641\u0638\u0020\u05e9\u05de\u05d9\u05e8\u05d4", 
       "\u05d9\u05e6\u05d9\u05d0\u05d4\u0020\u062e\u0631\u0648\u062c" 
   };

   char[] fileShortcutsEnglish = { '\u0041','\u0061','\u0065','\u0030' };
   char[] fileShortcutsArabic = { '\u062c','\u0641','\u062d','\u062e' };
   char[] fileShortcutsHebrew = { '\u05d7','\u05e4','\u05e9','\u05d9' };
   char[] fileShortcutsBidi   =   { '\u062c','\u0641','\u05de','\u05d9' };

   public jMenuX() 
   {

      JMenu fileMenu = new JMenu("English");
      JMenu Menu2 = new JMenu("Menu2 \u0639\u0631\u0628\u064a");
      JMenu Menu3 = new JMenu("Menu3 \u05e2\u05d1\u05e8\u05d9\u05ea");
      JMenu Menu4 = new JMenu("Menu4 Bidi\u05e2\u05d1\u05e8\u05d9\u05ea\u0020\u0639\u0631\u0628\u064a");
      fileMenu.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
      Menu2.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
      Menu3.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
      Menu4.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
      fileMenu.setMnemonic('G');
      Menu2.setMnemonic('\u0639');
      Menu3.setMnemonic('\u05e2');
      Menu4.setMnemonic('\u05d1');


      for (int i=0; i < fileItemsEnglish.length; i++) 
      {
          JMenuItem item = new JMenuItem(fileItemsEnglish[i]);
          item.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
          item.setMnemonic(fileShortcutsEnglish[i]);
          item.addActionListener(this);
          fileMenu.add(item);
      }

      for (int i=0; i < fileItemsArabic.length; i++) 
      {
          JMenuItem item = new JMenuItem(fileItemsArabic[i]);
          item.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
          item.setMnemonic(fileShortcutsArabic[i]);
          item.addActionListener(this);
          Menu2.add(item);
      }


      for (int i=0; i < fileItemsHebrew.length; i++) 
      {
          JMenuItem item = new JMenuItem(fileItemsHebrew[i]);
          item.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
          item.setMnemonic(fileShortcutsHebrew[i]);
          item.addActionListener(this);
          Menu3.add(item);
      }
      for (int i=0; i < fileItemsBidi.length; i++) 
      {
          JMenuItem item = new JMenuItem(fileItemsBidi[i]);
          item.setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
          item.setMnemonic(fileShortcutsBidi[i]);
          item.addActionListener(this);
          Menu4.add(item);
      }

this.setPreferredSize( new Dimension(400, 40));
      add(fileMenu);
      add(Menu2);
      add(Menu3);
      add(Menu4);
     }

    public void actionPerformed(ActionEvent e)
    {
        try
        {
           setFont(new Font("Lucida Sans Regular",Font.PLAIN,14));
           pane.getStyledDocument().insertString(0 ,"Action ["+e.getActionCommand()+"] performed!\n", null);
        }
        catch (Exception ex)
                {;}

     }
}


WorkAround:
======================================================================

Name: yyT116575			Date: 08/08/2001


java version "1.4.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta-b65)
Java HotSpot(TM) Client VM (build 1.4.0-beta-b65, mixed mode)


OS: Windows 2000

the bug appears when running this code.
JMenuBar /JMenu doesn't work correctly when arabic orientation

How to reproduce the bug:
when running the code:
click on "A Menu" menu then click on the right arrow keys the focus goes to left
instead it's acting as it is english orientation,
right arrow key goes to the left
left arrow key goes to the right.

also the popup menu displayed to the right.



import java.awt.*;
import java.awt.event.*;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.ButtonGroup;
import javax.swing.JMenuBar;
import javax.swing.KeyStroke;
import javax.swing.ImageIcon;

import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JFrame;

/*
 * This class exists solely to show you what menus look like.
 * It has no menu-related event handling.
 */
public class test extends JFrame {
  JTextArea output;
  JScrollPane scrollPane;

  public test() {
    JMenuBar menuBar;
    JMenu menu, submenu;
    JMenuItem menuItem;
    JCheckBoxMenuItem cbMenuItem;
    JRadioButtonMenuItem rbMenuItem;

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

    //Add regular components to the window, using the default BorderLayout.
    Container contentPane = getContentPane();
    output = new JTextArea(5, 30);
    output.setEditable(false);
    scrollPane = new JScrollPane(output);
    contentPane.add(scrollPane, BorderLayout.CENTER);
    contentPane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

    //Create the menu bar.
    menuBar = new JMenuBar();
    menuBar.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    setJMenuBar(menuBar);

    //Build the first menu.
    menu = new JMenu("A Menu");
    menu.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menu.setMnemonic(KeyEvent.VK_A);
    menu.getAccessibleContext().setAccessibleDescription(
        "The only menu in this program that has menu items");
    menuBar.add(menu);

    //a group of JMenuItems
    menuItem = new JMenuItem("A text-only menu item", KeyEvent.VK_T);
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(
        KeyEvent.VK_1, ActionEvent.ALT_MASK));
    menuItem.getAccessibleContext().setAccessibleDescription(
        "This doesn't really do anything");
    menu.add(menuItem);

    menuItem = new JMenuItem("Both text and icon",
        new ImageIcon("images/middle.gif"));
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menuItem.setMnemonic(KeyEvent.VK_B);
    menu.add(menuItem);

    menuItem = new JMenuItem(new ImageIcon("images/middle.gif"));
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menuItem.setMnemonic(KeyEvent.VK_D);
    menu.add(menuItem);

    //a group of radio button menu items
    menu.addSeparator();
    ButtonGroup group = new ButtonGroup();

    rbMenuItem = new JRadioButtonMenuItem("A radio button menu item");
    rbMenuItem.setSelected(true);
    rbMenuItem.setMnemonic(KeyEvent.VK_R);
    group.add(rbMenuItem);
    menu.add(rbMenuItem);

    rbMenuItem = new JRadioButtonMenuItem("Another one");
    rbMenuItem.setMnemonic(KeyEvent.VK_O);
    group.add(rbMenuItem);
    menu.add(rbMenuItem);

    //a group of check box menu items
    menu.addSeparator();
    cbMenuItem = new JCheckBoxMenuItem("A check box menu item");
    cbMenuItem.setMnemonic(KeyEvent.VK_C);
    menu.add(cbMenuItem);

    cbMenuItem = new JCheckBoxMenuItem("Another one");
    cbMenuItem.setMnemonic(KeyEvent.VK_H);
    menu.add(cbMenuItem);

    //a submenu
    menu.addSeparator();
    submenu = new JMenu("A submenu");
    submenu.setMnemonic(KeyEvent.VK_S);

    menuItem = new JMenuItem("An item in the submenu");
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(
        KeyEvent.VK_2, ActionEvent.ALT_MASK));
    submenu.add(menuItem);

    menuItem = new JMenuItem("Another item");
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    submenu.add(menuItem);
    menu.add(submenu);

    //Build second menu in the menu bar.
    menu = new JMenu("Another Menu");
    menu.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menu.setMnemonic(KeyEvent.VK_N);
    menu.getAccessibleContext().setAccessibleDescription(
        "This menu does nothing");
    menuItem = new JMenuItem("An item in the submenu");
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(
        KeyEvent.VK_2, ActionEvent.ALT_MASK));
    menu.add(menuItem);
        
        
    menuBar.add(menu);
        
    menu = new JMenu("Another Menu");
    menu.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menu.setMnemonic(KeyEvent.VK_N);
    menu.getAccessibleContext().setAccessibleDescription(
        "This menu does nothing");
    menuItem = new JMenuItem("An item in the submenu");
    menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(
        KeyEvent.VK_2, ActionEvent.ALT_MASK));
    menu.add(menuItem);
    menuBar.add(menu);
        
  }

  public static void main(String[] args) {
    test window = new test();

    window.setTitle("MenuLookDemo");
    window.setSize(450, 260);
    window.setVisible(true);
  }
}
(Review ID: 129596)
======================================================================

Name: yyT116575			Date: 08/23/2001


java version "1.4.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta-b65)
Java HotSpot(TM) Client VM (build 1.4.0-beta-b65, mixed mode)

in RIGHT_TO_LEFT orientation the LEFT & RIGHT keys work go in the wrong visiual direction.

in the following example when menu "two" is selected the left key should take us to menu "Three" .. instead it goes to "one".

source:

import javax.swing.*;

public class MenuTest extends JFrame {
  
  public MenuTest() {
    JMenuBar bar = new JMenuBar();
    bar.setComponentOrientation(java.awt.ComponentOrientation.RIGHT_TO_LEFT);

    JMenu menu = new JMenu("One");
    menu.add(new JMenuItem("1.1"));
    menu.add(new JMenuItem("1.2"));
    bar.add(menu);
    
    menu = new JMenu("Two");
    menu.add(new JMenuItem("2.1"));
    menu.add(new JMenuItem("2.2"));
    bar.add(menu);
    
    menu = new JMenu("Three");
    menu.add(new JMenuItem("3.1"));
    menu.add(new JMenuItem("3.2"));
    bar.add(menu);
    
    setJMenuBar(bar);
    pack();
    setSize(300, 400);
    setVisible(true);
  }
  
  public static void main(String args[]) {
    new MenuTest();
  }
}
(Review ID: 130451)
======================================================================

Comments
EVALUATION this bug was addressed by the fix for 4374406 [Mnemonics underscore fails to display correctly under joined Arabic characters] closing as dup
12-08-2005