All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.awt.Mnemonics Maven / Gradle / Ivy

There is a newer version: RELEASE240
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Contributors: Maxym Mykhalchuk
 */
package org.openide.awt;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.openide.util.Utilities;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javax.swing.AbstractButton;
import javax.swing.JLabel;
import javax.swing.UIManager;


/**
 * Support class for setting button, menu, and label text strings with mnemonics.
 * @author Maxym Mykhalchuk
 * @since 3.37
 * @see Issue #26640
 */
public final class Mnemonics extends Object {
    /** Private constructor in order that this class is never instantiated. */
    private Mnemonics() {
    }

    /**
     * Actual setter of the text & mnemonics for the AbstractButton/JLabel or
     * their subclasses.
     * @param item AbstractButton/JLabel
     * @param text new label
     */
    private static void setLocalizedText2(Object item, String text) {
        // #17664. Handle null text also.
        // & in HTML should be ignored
        if (text == null) { // NOI18N
            setText(item, null);

            return;
        }

        int i = findMnemonicAmpersand(text);

        setMnemonicIndex(item, -1);
        if (i < 0) {
            // no '&' - don't set the mnemonic
            setText(item, text);
            setMnemonic(item, 0);
        } else {
            setText(item, text.substring(0, i) + text.substring(i + 1));
            //#67807 no mnemonics on macosx
            if (isAquaLF()) {
                setMnemonic(item, 0);
            } else {
                char ch = text.charAt(i + 1);
                if (text.startsWith("")) { // NOI18N
                    // Workaround for JDK bug #6510775
                    setText(item, text.substring(0, i) + "" + ch + "" + text.substring(i + 2)); // NOI18N
                    i += 3; // just in case it gets fixed
                }
                if (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || ((ch >= '0') && (ch <= '9'))) {
                    // it's latin character or arabic digit,
                    // setting it as mnemonics
                    setMnemonic(item, ch);
                    
                    // If it's something like "Save &As", we need to set another
                    // mnemonic index (at least under 1.4 or later)
                    // see #29676
                    setMnemonicIndex(item, i);
                } else {
                    // it's non-latin, getting the latin correspondance
                    try {
                        int latinCode = getLatinKeycode(ch);
                        setMnemonic(item, latinCode);
                        setMnemonicIndex(item, i);
                    } catch (MissingResourceException e) {
                        Logger.getLogger(Mnemonics.class.getName()).info("Mapping from a non-Latin character '"+ch+ 
                                "' not found in a localized (branded) version of "+
                                "openide/awt/src/org/openide/awt/Mnemonics.properties - "+
                                "mnemonic cannot be assigned in "+text);
                    }
                }
            }
        }
    }

    /**
     * Sets the text for a menu item or other subclass of AbstractButton.
     * 

Examples:

* * * * * * * *
example
Input String View under JDK 1.4 or later
Save &As Save As
Rock & Roll Rock & Roll
Drag & &Drop Drag & Drop
&Файл Файл
* @param item a button whose text will be changed * @param text new label */ public static void setLocalizedText(AbstractButton item, String text) { setLocalizedText2(item, text); } /** * Sets the text for the label or other subclass of JLabel. * For details see {@link #setLocalizedText(AbstractButton, String)}. * @param item a label whose text will be set * @param text new label */ public static void setLocalizedText(JLabel item, String text) { setLocalizedText2(item, text); } /** * Searches for an ampersand in a string which indicates a mnemonic. * Recognizes the following cases: *
    *
  • "Drag & Drop", "Ampersand ('&')" - don't have mnemonic ampersand. * "&" is not found before " " (space), or if enclosed in "'" * (single quotation marks). *
  • "&File", "Save &As..." - do have mnemonic ampersand. *
  • "Rock & Ro&ll", "Underline the '&' &character" - also do have * mnemonic ampersand, but the second one. *
  • "<html><b>R&amp;D</b> departmen&t" - has mnemonic * ampersand before "t". * Ampersands in HTML texts that are part of entity are ignored. *
* @param text text to search * @return the position of mnemonic ampersand in text, or -1 if there is none */ public static int findMnemonicAmpersand(String text) { int i = -1; boolean isHTML = text.startsWith(""); do { // searching for the next ampersand i = text.indexOf('&', i + 1); if ((i >= 0) && ((i + 1) < text.length())) { if (isHTML) { boolean startsEntity = false; for (int j = i + 1; j < text.length(); j++) { char c = text.charAt(j); if (c == ';') { startsEntity = true; break; } if (!Character.isLetterOrDigit(c)) { break; } } if (!startsEntity) { return i; } } else { // before ' ' if (text.charAt(i + 1) == ' ') { continue; // before ', and after ' } else if ((text.charAt(i + 1) == '\'') && (i > 0) && (text.charAt(i - 1) == '\'')) { continue; } // ampersand is marking mnemonics return i; } } } while (i >= 0); return -1; } /** * Gets the Latin symbol which corresponds * to some non-Latin symbol on the localized keyboard. * The search is done via lookup of Resource bundle * for pairs having the form (e.g.) MNEMONIC_\u0424=A. * @param localeChar non-Latin character or a punctuator to be used as mnemonic * @return character on latin keyboard, corresponding to the locale character, * or the appropriate VK_*** code (if there's no latin character * "under" the non-Latin one */ private static int getLatinKeycode(char localeChar) throws MissingResourceException { // associated should be a latin character, arabic digit // or an integer (KeyEvent.VK_***) String str = getBundle().getString("MNEMONIC_" + localeChar); // NOI18N if (str.length() == 1) { return str.charAt(0); } else { return Integer.parseInt(str); } } /** * Wrapper for the * AbstractButton.setMnemonicIndex or * JLabel.setDisplayedMnemonicIndex method. * @param item AbstractButton/JLabel or subclasses * @param index Index of the Character to underline under JDK1.4 * @param latinCode Latin Character Keycode to underline under JDK1.3 */ private static void setMnemonicIndex(Object item, int index) { if (item instanceof AbstractButton) { AbstractButton b = (AbstractButton) item; b.putClientProperty(PROP_DISPLAYED_MNEMONIC_INDEX, index); b.removePropertyChangeListener(PROP_DISPLAYED_MNEMONIC_INDEX, MNEMONIC_INDEX_LISTENER); b.setDisplayedMnemonicIndex(index); b.addPropertyChangeListener(PROP_DISPLAYED_MNEMONIC_INDEX, MNEMONIC_INDEX_LISTENER); } else if (item instanceof JLabel) { ((JLabel) item).setDisplayedMnemonicIndex(index); } } private static final String PROP_TEXT = "text"; // NOI18N private static final String PROP_MNEMONIC = "mnemonic"; // NOI18N private static final String PROP_DISPLAYED_MNEMONIC_INDEX = "displayedMnemonicIndex"; // NOI18N private static final PropertyChangeListener MNEMONIC_INDEX_LISTENER = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { AbstractButton b = (AbstractButton) evt.getSource(); if (b.getDisplayedMnemonicIndex() == -1) { Integer mnemonic = (Integer) b.getClientProperty(PROP_MNEMONIC); Integer index = (Integer) b.getClientProperty(PROP_DISPLAYED_MNEMONIC_INDEX); if (mnemonic != null && index != null && Utilities.compareObjects(b.getText(), b.getClientProperty(PROP_TEXT))) { b.setMnemonic(mnemonic); b.setDisplayedMnemonicIndex(index); } } } }; /** * Wrapper for AbstractButton/JLabel.setText * @param item AbstractButton/JLabel * @param text the text to set */ private static void setText(Object item, String text) { if (item instanceof AbstractButton) { AbstractButton b = (AbstractButton) item; b.putClientProperty(PROP_TEXT, text); b.setText(text); } else { ((JLabel) item).setText(text); } } /** * Wrapper for AbstractButton.setMnemonic and JLabel.setDisplayedMnemonic * @param item AbstractButton/JLabel * @param mnem Mnemonic char to set, latin [a-z,A-Z], digit [0-9], or any VK_ code */ private static void setMnemonic(Object item, int mnem) { if (isAquaLF()) { // there shall be no mnemonics on macosx. //#55864 return; } if ((mnem >= 'a') && (mnem <= 'z')) { mnem = mnem + ('A' - 'a'); } if (item instanceof AbstractButton) { AbstractButton b = (AbstractButton) item; b.putClientProperty(PROP_MNEMONIC, mnem); b.setMnemonic(mnem); } else { ((JLabel) item).setDisplayedMnemonic(mnem); } } /** * Getter for the used Resource bundle (org.openide.awt.Mnemonics). * Used to avoid calling
ResourceBundle.getBundle(...) * many times in defferent places of the code. * Does no caching, it's simply an utility method. */ private static ResourceBundle getBundle() { return ResourceBundle.getBundle("org.openide.awt.Mnemonics"); // NOI18N } static boolean isAquaLF() { return "Aqua".equals( UIManager.getLookAndFeel().getID() ); //NOI18N } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy