Search in sources :

Example 36 with JMenuItem

use of javax.swing.JMenuItem in project processing by processing.

the class Recent method updateMenuRecord.

private static void updateMenuRecord(JMenu menu, final Record rec, String sketchbookPath) {
    try {
        String recPath = new File(rec.getPath()).getParent();
        String purtyPath = null;
        if (recPath.startsWith(sketchbookPath)) {
            purtyPath = "sketchbook → " + recPath.substring(sketchbookPath.length() + 1);
        } else {
            List<Mode> modes = base.getModeList();
            for (Mode mode : modes) {
                File examplesFolder = mode.getExamplesFolder();
                String examplesPath = examplesFolder.getAbsolutePath();
                if (recPath.startsWith(examplesPath)) {
                    String modePrefix = mode.getTitle() + " ";
                    if (mode.getTitle().equals("Standard")) {
                        // "Standard examples" is dorky
                        modePrefix = "";
                    }
                    purtyPath = modePrefix + "examples → " + recPath.substring(examplesPath.length() + 1);
                    break;
                }
                if (mode.coreLibraries != null) {
                    for (Library lib : mode.coreLibraries) {
                        examplesFolder = lib.getExamplesFolder();
                        examplesPath = examplesFolder.getAbsolutePath();
                        if (recPath.startsWith(examplesPath)) {
                            purtyPath = lib.getName() + " examples → " + recPath.substring(examplesPath.length() + 1);
                            break;
                        }
                    }
                }
                if (mode.contribLibraries != null) {
                    for (Library lib : mode.contribLibraries) {
                        examplesFolder = lib.getExamplesFolder();
                        examplesPath = examplesFolder.getAbsolutePath();
                        if (recPath.startsWith(examplesPath)) {
                            purtyPath = lib.getName() + " examples → " + recPath.substring(examplesPath.length() + 1);
                            break;
                        }
                    }
                }
            }
        }
        if (purtyPath == null) {
            String homePath = System.getProperty("user.home");
            if (recPath.startsWith(homePath)) {
                // Not localized, but this is gravy. It'll work on OS X & EN Windows
                String desktopPath = homePath + File.separator + "Desktop";
                if (recPath.startsWith(desktopPath)) {
                    purtyPath = "Desktop → " + recPath.substring(desktopPath.length() + 1);
                } else {
                    //purtyPath = "⌂ → " + recPath.substring(homePath.length() + 1);
                    //purtyPath = "Home → " + recPath.substring(homePath.length() + 1);
                    String userName = new File(homePath).getName();
                    //purtyPath = "⌂ " + userName + " → " + recPath.substring(homePath.length() + 1);
                    purtyPath = userName + " → " + recPath.substring(homePath.length() + 1);
                }
            } else {
                purtyPath = recPath;
            }
        }
        //      JMenuItem item = new JMenuItem(rec.getName() + " | " + purtyPath);
        JMenuItem item = new JMenuItem(purtyPath);
        item.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                // Base will call handle() (below) which will cause this entry to
                // be removed from the list and re-added to the end. If already
                // opened, Base will bring the window forward, and also call handle()
                // so that it's re-queued to the newest slot in the Recent menu.
                base.handleOpen(rec.path);
            //          if (rec.sketch == null) {
            //            // this will later call 'add' to put it back on the stack
            //            base.handleOpen(rec.path); //, rec.state);
            ////            int index = findRecord(rec);
            ////            if (index != -1) {
            ////              records.remove(index);  // remove from the list
            ////              save();  // write the recent file with the latest
            ////            }
            //          } else {
            ////              System.out.println("sketch not null in handleOpen: " + record.getPath());
            //          }
            }
        });
        //menu.add(item);
        menu.insert(item, 0);
    } catch (Exception e) {
        // Strange things can happen... report them for the geeky and move on:
        // https://github.com/processing/processing/issues/2463
        e.printStackTrace();
    }
}
Also used : ActionListener(java.awt.event.ActionListener) ActionEvent(java.awt.event.ActionEvent) Mode(processing.app.Mode) Library(processing.app.Library) JMenuItem(javax.swing.JMenuItem) File(java.io.File) IOException(java.io.IOException)

Example 37 with JMenuItem

use of javax.swing.JMenuItem in project processing by processing.

the class Toolkit method newJMenuItemShift.

/**
   * Like newJMenuItem() but adds shift as a modifier for the shortcut.
   */
public static JMenuItem newJMenuItemShift(String title, int what) {
    JMenuItem menuItem = new JMenuItem(title);
    int modifiers = awtToolkit.getMenuShortcutKeyMask();
    modifiers |= ActionEvent.SHIFT_MASK;
    menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers));
    return menuItem;
}
Also used : JMenuItem(javax.swing.JMenuItem)

Example 38 with JMenuItem

use of javax.swing.JMenuItem in project processing by processing.

the class Toolkit method newJMenuItem.

/**
   * A software engineer, somewhere, needs to have their abstraction
   * taken away. Who crafts the sort of API that would require a
   * five-line helper function just to set the shortcut key for a
   * menu item?
   */
public static JMenuItem newJMenuItem(String title, int what) {
    JMenuItem menuItem = new JMenuItem(title);
    int modifiers = awtToolkit.getMenuShortcutKeyMask();
    menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers));
    return menuItem;
}
Also used : JMenuItem(javax.swing.JMenuItem)

Example 39 with JMenuItem

use of javax.swing.JMenuItem in project processing by processing.

the class Toolkit method newJMenuItemAlt.

/**
   * Same as newJMenuItem(), but adds the ALT (on Linux and Windows)
   * or OPTION (on Mac OS X) key as a modifier. This function should almost
   * never be used, because it's bad for non-US keyboards that use ALT in
   * strange and wondrous ways.
   */
public static JMenuItem newJMenuItemAlt(String title, int what) {
    JMenuItem menuItem = new JMenuItem(title);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(what, SHORTCUT_ALT_KEY_MASK));
    return menuItem;
}
Also used : JMenuItem(javax.swing.JMenuItem)

Example 40 with JMenuItem

use of javax.swing.JMenuItem in project processing by processing.

the class Toolkit method setMenuMnemonics.

/**
   * Removes all mnemonics, then sets a mnemonic for each menu and menu item
   * recursively by these rules:
   * <ol>
   * <li> It tries to assign one of <a href="http://techbase.kde.org/Projects/Usability/HIG/Keyboard_Accelerators">
   * KDE's defaults</a>.</li>
   * <li> Failing that, it loops through the first letter of each word, where a word
   *  is a block of Unicode "alphabetical" chars, looking for an upper-case ASCII mnemonic
   *  that is not taken. This is to try to be relevant, by using a letter well-associated
   *  with the command. (MS guidelines) </li>
   * <li> Ditto, but with lowercase. </li>
   * <li> Next, it tries the second ASCII character, if its width &gt;= half the width of
   *  'A'. </li>
   * <li> If the first letters are all taken/non-ASCII, then it loops through the
   *  ASCII letters in the item, widest to narrowest, seeing if any of them is not taken.
   *  To improve readability, it discriminates against decenders (qypgj), imagining they
   *  have 2/3 their actual width. (MS guidelines: avoid decenders). It also discriminates
   *  against vowels, imagining they have 2/3 their actual width. (MS and Gnome guidelines:
   *  avoid vowels.) </li>
   * <li>Failing that, it will loop left-to-right for an available digit. This is a last
   *  resort because the normal setMnemonic dislikes them.</li>
   * <li> If that doesn't work, it doesn't assign a mnemonic. </li>
   * </ol>
   *
   * As a special case, strings starting "sketchbook → " have that bit ignored
   * because otherwise the Recent menu looks awful. However, the name <tt>"sketchbook →
   * Sketch"</tt>, for example, will have the 'S' of "Sketch" chosen, but the 's' of 'sketchbook
   * will get underlined.
   * No letter by an underscore will be assigned.
   * Disabled on Mac, per Apple guidelines.
   * <tt>menu</tt> may contain nulls.
   *
   * Author: George Bateman. Initial work Myer Nore.
   * @param menu
   *          A menu, a list of menus or an array of menu items to set mnemonics for.
   */
public static void setMenuMnemonics(JMenuItem... menu) {
    if (Platform.isMacOS())
        return;
    if (menu.length == 0)
        return;
    // The English is http://techbase.kde.org/Projects/Usability/HIG/Keyboard_Accelerators,
    // made lowercase.
    // Nothing but [a-z] except for '&' before mnemonics and regexes for changable text.
    final String[] kdePreDefStrs = { "&file", "&new", "&open", "open&recent", "&save", "save&as", "saveacop&y", "saveas&template", "savea&ll", "reloa&d", "&print", "printpre&view", "&import", "e&xport", "&closefile", "clos&eallfiles", "&quit", "&edit", "&undo", "re&do", "cu&t", "&copy", "&paste", "&delete", "select&all", "dese&lect", "&find", "find&next", "findpre&vious", "&replace", "&gotoline", "&view", "&newview", "close&allviews", "&splitview", "&removeview", "splitter&orientation", "&horizontal", "&vertical", "view&mode", "&fullscreenmode", "&zoom", "zoom&in", "zoom&out", "zoomtopage&width", "zoomwhole&page", "zoom&factor", "&insert", "&format", "&go", "&up", "&back", "&forward", "&home", "&go", "&previouspage", "&nextpage", "&firstpage", "&lastpage", "read&updocument", "read&downdocument", "&back", "&forward", "&gotopage", "&bookmarks", "&addbookmark", "bookmark&tabsasfolder", "&editbookmarks", "&newbookmarksfolder", "&tools", "&settings", "&toolbars", "configure&shortcuts", "configuretool&bars", "&configure.*", "&help", ".+&handbook", "&whatsthis", "report&bug", "&aboutprocessing", "about&kde", // de
    "&beenden", // de
    "&suchen", // Preferências; pt
    "&preferncias", // Preferências; pt
    "&sair", // fr
    "&rechercher" };
    Pattern[] kdePreDefPats = new Pattern[kdePreDefStrs.length];
    for (int i = 0; i < kdePreDefStrs.length; i++) {
        kdePreDefPats[i] = Pattern.compile(kdePreDefStrs[i].replace("&", ""));
    }
    final Pattern nonAAlpha = Pattern.compile("[^A-Za-z]");
    FontMetrics fmTmp = null;
    for (JMenuItem m : menu) {
        if (m != null) {
            fmTmp = m.getFontMetrics(m.getFont());
            break;
        }
    }
    // All null menuitems; would fail.
    if (fmTmp == null)
        return;
    // Hack for accessing variable in comparator.
    final FontMetrics fm = fmTmp;
    final Comparator<Character> charComparator = new Comparator<Character>() {

        char[] baddies = "qypgjaeiouQAEIOU".toCharArray();

        public int compare(Character ch1, Character ch2) {
            // Discriminates against descenders for readability, per MS
            // Human Interface Guide, and vowels per MS and Gnome.
            float w1 = fm.charWidth(ch1), w2 = fm.charWidth(ch2);
            for (char bad : baddies) {
                if (bad == ch1)
                    w1 *= 0.66f;
                if (bad == ch2)
                    w2 *= 0.66f;
            }
            return (int) Math.signum(w2 - w1);
        }
    };
    // Holds only [0-9a-z], not uppercase.
    // Prevents X != x, so "Save" and "Save As" aren't both given 'a'.
    final List<Character> taken = new ArrayList<Character>(menu.length);
    char firstChar;
    char[] cleanChars;
    Character[] cleanCharas;
    // METHOD 1: attempt to assign KDE defaults.
    for (JMenuItem jmi : menu) {
        if (jmi == null)
            continue;
        if (jmi.getText() == null)
            continue;
        // Reset all mnemonics.
        jmi.setMnemonic(0);
        String asciiName = nonAAlpha.matcher(jmi.getText()).replaceAll("");
        String lAsciiName = asciiName.toLowerCase();
        for (int i = 0; i < kdePreDefStrs.length; i++) {
            if (kdePreDefPats[i].matcher(lAsciiName).matches()) {
                char mnem = asciiName.charAt(kdePreDefStrs[i].indexOf("&"));
                jmi.setMnemonic(mnem);
                jmi.setDisplayedMnemonicIndex(jmi.getText().indexOf(mnem));
                // to lowercase
                taken.add((char) (mnem | 32));
                break;
            }
        }
    }
    // Where KDE defaults fail, use an algorithm.
    algorithmicAssignment: for (JMenuItem jmi : menu) {
        if (jmi == null)
            continue;
        if (jmi.getText() == null)
            continue;
        // Already assigned.
        if (jmi.getMnemonic() != 0)
            continue;
        // The string can't be made lower-case as that would spoil
        // the width comparison.
        String cleanString = jmi.getText();
        if (cleanString.startsWith("sketchbook → "))
            cleanString = cleanString.substring(13);
        if (cleanString.length() == 0)
            continue;
        // First, ban letters by underscores.
        final List<Character> banned = new ArrayList<Character>();
        for (int i = 0; i < cleanString.length(); i++) {
            if (cleanString.charAt(i) == '_') {
                if (i > 0)
                    banned.add(Character.toLowerCase(cleanString.charAt(i - 1)));
                if (i + 1 < cleanString.length())
                    banned.add(Character.toLowerCase(cleanString.charAt(i + 1)));
            }
        }
        // because there could be non-ASCII letters in a word.
        for (String wd : cleanString.split("[^\\p{IsAlphabetic}]")) {
            if (wd.length() == 0)
                continue;
            firstChar = wd.charAt(0);
            if (taken.contains(Character.toLowerCase(firstChar)))
                continue;
            if (banned.contains(Character.toLowerCase(firstChar)))
                continue;
            if ('A' <= firstChar && firstChar <= 'Z') {
                jmi.setMnemonic(firstChar);
                jmi.setDisplayedMnemonicIndex(jmi.getText().indexOf(firstChar));
                // tolowercase
                taken.add((char) (firstChar | 32));
                continue algorithmicAssignment;
            }
        }
        // METHOD 3: Lowercase starts of words.
        for (String wd : cleanString.split("[^\\p{IsAlphabetic}]")) {
            if (wd.length() == 0)
                continue;
            firstChar = wd.charAt(0);
            if (taken.contains(Character.toLowerCase(firstChar)))
                continue;
            if (banned.contains(Character.toLowerCase(firstChar)))
                continue;
            if ('a' <= firstChar && firstChar <= 'z') {
                jmi.setMnemonic(firstChar);
                jmi.setDisplayedMnemonicIndex(jmi.getText().indexOf(firstChar));
                // is lowercase
                taken.add(firstChar);
                continue algorithmicAssignment;
            }
        }
        // METHOD 4: Second wide-enough ASCII letter.
        cleanString = nonAAlpha.matcher(jmi.getText()).replaceAll("");
        if (cleanString.length() >= 2) {
            char ascii2nd = cleanString.charAt(1);
            if (!taken.contains((char) (ascii2nd | 32)) && !banned.contains((char) (ascii2nd | 32)) && fm.charWidth('A') <= 2 * fm.charWidth(ascii2nd)) {
                jmi.setMnemonic(ascii2nd);
                jmi.setDisplayedMnemonicIndex(jmi.getText().indexOf(ascii2nd));
                taken.add((char) (ascii2nd | 32));
                continue algorithmicAssignment;
            }
        }
        // METHOD 5: charComparator over all ASCII letters.
        cleanChars = cleanString.toCharArray();
        cleanCharas = new Character[cleanChars.length];
        for (int i = 0; i < cleanChars.length; i++) {
            cleanCharas[i] = new Character(cleanChars[i]);
        }
        // sorts in increasing order
        Arrays.sort(cleanCharas, charComparator);
        for (char mnem : cleanCharas) {
            if (taken.contains(Character.toLowerCase(mnem)))
                continue;
            if (banned.contains(Character.toLowerCase(mnem)))
                continue;
            // NB: setMnemonic(char) doesn't want [^A-Za-z]
            jmi.setMnemonic(mnem);
            jmi.setDisplayedMnemonicIndex(jmi.getText().indexOf(mnem));
            taken.add(Character.toLowerCase(mnem));
            continue algorithmicAssignment;
        }
        // METHOD 6: Digits as last resort.
        for (char digit : jmi.getText().replaceAll("[^0-9]", "").toCharArray()) {
            if (taken.contains(digit))
                continue;
            if (banned.contains(digit))
                continue;
            jmi.setMnemonic(KeyEvent.VK_0 + digit - '0');
            // setDisplayedMnemonicIndex() unneeded: no case issues.
            taken.add(digit);
            continue algorithmicAssignment;
        }
    }
    // Finally, RECURSION.
    for (JMenuItem jmi : menu) {
        if (jmi instanceof JMenu)
            setMenuMnemsInside((JMenu) jmi);
    }
}
Also used : Pattern(java.util.regex.Pattern) ArrayList(java.util.ArrayList) Comparator(java.util.Comparator) FontMetrics(java.awt.FontMetrics) StringList(processing.data.StringList) List(java.util.List) ArrayList(java.util.ArrayList) JMenuItem(javax.swing.JMenuItem) JMenu(javax.swing.JMenu)

Aggregations

JMenuItem (javax.swing.JMenuItem)1138 ActionEvent (java.awt.event.ActionEvent)559 ActionListener (java.awt.event.ActionListener)463 JMenu (javax.swing.JMenu)373 JPopupMenu (javax.swing.JPopupMenu)229 JMenuBar (javax.swing.JMenuBar)104 AbstractAction (javax.swing.AbstractAction)90 JCheckBoxMenuItem (javax.swing.JCheckBoxMenuItem)76 ArrayList (java.util.ArrayList)72 JPanel (javax.swing.JPanel)70 Point (java.awt.Point)65 JSeparator (javax.swing.JSeparator)63 File (java.io.File)61 JLabel (javax.swing.JLabel)61 BorderLayout (java.awt.BorderLayout)57 JButton (javax.swing.JButton)54 Component (java.awt.Component)53 ButtonGroup (javax.swing.ButtonGroup)50 Dimension (java.awt.Dimension)46 MouseEvent (java.awt.event.MouseEvent)45