From 914b528f72ecf7a7fb9a11789ed6b07975c30b6a Mon Sep 17 00:00:00 2001 From: GKFX Date: Tue, 25 Feb 2014 19:51:25 +0000 Subject: [PATCH 01/10] Menu mnemonics #51 Added Toolkit.setMenuMnemonics(JMenuItem...) and Toolkit.setMenuMnemonics(JMenuBar). --- app/src/processing/app/Editor.java | 53 +++-- app/src/processing/app/EditorHeader.java | 1 + app/src/processing/app/Mode.java | 5 +- app/src/processing/app/Recent.java | 3 +- app/src/processing/app/Toolkit.java | 217 +++++++++++++++++- .../app/contrib/ContributionPanel.java | 4 +- 6 files changed, 254 insertions(+), 29 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 3463555e0..5d5d12144 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -408,6 +408,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } }); modeMenu.add(addLib); + Toolkit.setMenuMnemonics(modeMenu); } @@ -551,6 +552,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // } menubar.add(buildHelpMenu()); + Toolkit.setMenuMnemonics(menubar); setJMenuBar(menubar); } @@ -874,8 +876,9 @@ public abstract class Editor extends JFrame implements RunnerListener { sketchMenu.add(mi); } - sketchMenu.addSeparator(); - + if (runItems.length != 0) + sketchMenu.addSeparator(); + sketchMenu.add(mode.getImportMenu()); item = Toolkit.newJMenuItem("Show Sketch Folder", 'K'); @@ -2587,15 +2590,11 @@ public abstract class Editor extends JFrame implements RunnerListener { * Returns the edit popup menu. */ class TextAreaPopup extends JPopupMenu { - JMenuItem cutItem; - JMenuItem copyItem; - JMenuItem discourseItem; - JMenuItem referenceItem; - + JMenuItem cutItem, copyItem, discourseItem, pasteItem, + selectAllItem, commUncommItem, incIndItem, decIndItem, + referenceItem; public TextAreaPopup() { - JMenuItem item; - cutItem = new JMenuItem("Cut"); cutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -2620,47 +2619,47 @@ public abstract class Editor extends JFrame implements RunnerListener { }); this.add(discourseItem); - item = new JMenuItem("Paste"); - item.addActionListener(new ActionListener() { + pasteItem = new JMenuItem("Paste"); + pasteItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handlePaste(); } }); - this.add(item); + this.add(pasteItem); - item = new JMenuItem("Select All"); - item.addActionListener(new ActionListener() { + selectAllItem = new JMenuItem("Select All"); + selectAllItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleSelectAll(); } }); - this.add(item); + this.add(selectAllItem); this.addSeparator(); - item = new JMenuItem("Comment/Uncomment"); - item.addActionListener(new ActionListener() { + commUncommItem = new JMenuItem("Comment/Uncomment"); + commUncommItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleCommentUncomment(); } }); - this.add(item); + this.add(commUncommItem); - item = new JMenuItem("Increase Indent"); - item.addActionListener(new ActionListener() { + incIndItem = new JMenuItem("Increase Indent"); + incIndItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleIndentOutdent(true); } }); - this.add(item); + this.add(incIndItem); - item = new JMenuItem("Decrease Indent"); - item.addActionListener(new ActionListener() { + decIndItem = new JMenuItem("Decrease Indent"); + decIndItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleIndentOutdent(false); } }); - this.add(item); + this.add(decIndItem); this.addSeparator(); @@ -2671,6 +2670,10 @@ public abstract class Editor extends JFrame implements RunnerListener { } }); this.add(referenceItem); + + Toolkit.setMenuMnemonics(cutItem, copyItem, discourseItem, + pasteItem, selectAllItem, commUncommItem, incIndItem, + decIndItem, referenceItem); } // if no text is selected, disable copy and cut menu items @@ -2699,4 +2702,4 @@ public abstract class Editor extends JFrame implements RunnerListener { super.show(component, x, y); } } -} \ No newline at end of file +} diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java index 334d0e91d..493122202 100644 --- a/app/src/processing/app/EditorHeader.java +++ b/app/src/processing/app/EditorHeader.java @@ -593,6 +593,7 @@ public class EditorHeader extends JComponent { menu.add(item); } } + Toolkit.setMenuMnemonics(menu); } diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index 0efa9c72e..068258d2c 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -386,6 +386,9 @@ public abstract class Mode { // Add a list of all sketches and subfolders toolbarMenu.addSeparator(); base.populateSketchbookMenu(toolbarMenu); + + Toolkit.setMenuMnemonics(toolbarMenu); + // boolean found = false; // try { // found = base.addSketches(toolbarMenu, base.getSketchbookFolder(), true); @@ -1059,4 +1062,4 @@ public abstract class Mode { // public void handleNewReplace() { // base.handleNewReplace(); // } -} \ No newline at end of file +} diff --git a/app/src/processing/app/Recent.java b/app/src/processing/app/Recent.java index 4af3a566c..f002fc604 100644 --- a/app/src/processing/app/Recent.java +++ b/app/src/processing/app/Recent.java @@ -198,6 +198,7 @@ public class Recent { //menu.add(item); menu.insert(item, 0); } + Toolkit.setMenuMnemonics(menu); } @@ -363,4 +364,4 @@ public class Recent { // return getPath().equals(r.getPath()); // } } -} \ No newline at end of file +} diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index e549371af..96f3ad570 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -24,6 +24,7 @@ package processing.app; import java.awt.Dimension; import java.awt.Font; import java.awt.FontFormatException; +import java.awt.FontMetrics; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; @@ -43,6 +44,8 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -50,6 +53,7 @@ import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; +import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JRootPane; import javax.swing.KeyStroke; @@ -112,6 +116,218 @@ public class Toolkit { return menuItem; } + /** + * Removes all mnemonics, then sets a mnemonic for each menu and menu item + * recursively by these rules: + *
    + *
  1. It tries to assign one of + * KDE's defaults.
  2. + *
  3. 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)
  4. + *
  5. Ditto, but with lowercase.
  6. + *
  7. Next, it tries the second ASCII character, if its width >= half the width of + * 'A'.
  8. + *
  9. 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.
  10. + *
  11. Failing that, it will loop left-to-right for an available digit. This is a last + * resort because the normal setMnemonic dislikes them.
  12. + *
  13. If that doesn't work, it doesn't assign a mnemonic.
  14. + *
+ * + * As a special case, strings starting "sketchbook \u2192 " have that bit ignored + * because otherwise the Recent menu looks awful. However, the name "sketchbook \u2192 + * Sketch", 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. + * menu may contain nulls. + * @param menu + * A menu, a list of menus or an array of menu items to set mnemonics for. + * @param font + * A font for rendering character widths. + */ + public static void setMenuMnemonics(JMenuItem... menu) { + if (Base.isMacOS()) return; + if (menu.length == 0) return; + + // This list is the contents of http://techbase.kde.org/Projects/Usability/HIG/ + // Keyboard_Accelerators, made lowercase, with nothing but letters left except + // for ampersands before mnemonics and ".+" for changable text. (They are regexs.) + // Note that every ampersand MUST be followed by a lowercase ASCII letter. + final String[] kdePreDefs = { "&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&", "©", "&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", "&about[^k].*", "about&kde" }; + + final FontMetrics fm = menu[0].getFontMetrics(menu[0].getFont()); + final Comparator charComparator = new Comparator() { + public int compare(Character ch1, Character ch2) { + // Descriminates against decenders 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 : "qypgjaeiouQYPGJAEIOU".toCharArray()) { + if (bad == ch1) w1 *= 0.66; + if (bad == ch2) w2 *= 0.66; + } + return (int)Math.signum(w2 - w1); + } + }; + // taken holds only [a-z], not uppercase. + // Prevents uppercase letters != lowercase letters, so + // "Save" and "Save As" aren't both given 'a'. + final List taken = new ArrayList(menu.length); + char firstChar; + char[] w; // temp char array + Character[] word; + boolean foundYet = false; + + // METHOD 1: attempt to assign KDE defaults. + for (JMenuItem jmi : menu) { + if (jmi == null) continue; + jmi.setMnemonic(0); // Reset. + for (String kdePreDef : kdePreDefs) { + if (jmi.getText().toLowerCase().replaceAll("[^a-z]","").matches(kdePreDef.replace("&",""))) { + // mnem is lowercase: might be best to make uppercase if neccessary. + char mnem = kdePreDef.charAt(1+kdePreDef.indexOf("&")); + jmi.setMnemonic(jmi.getText().indexOf(Character.toString(mnem).toUpperCase()) < 0 ? + mnem : (char)(mnem-32)); + taken.add(mnem); + break; + } + } + } + + // Where KDE defaults fail, use an algorithm. + algorithmicAssaignment: + for (JMenuItem jmi : menu) { + if (jmi == null) continue; + if (jmi.getMnemonic() != 0) continue; // Already assigned. + + // The string can't be made lower-case as that would spoil + // the width comparison. + String cleanString = jmi.getText(); + if (cleanString.startsWith("sketchbook \u2192 ")) + cleanString = cleanString.substring(13); + + if (cleanString.length() == 0) continue; + + // First, ban letters by underscores. + final List banned = new ArrayList(); + 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))); + } + } + + // METHOD 2: Uppercase starts of words. + // Splitting into blocks of ASCII letters wouldn't work + // 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); + taken.add((char)(firstChar | 32)); // tolowercase + continue algorithmicAssaignment; + } + } + + // 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); + taken.add(firstChar); // is lowercase + continue algorithmicAssaignment; + } + } + + // METHOD 4: Second ASCII letter. + cleanString = cleanString.replaceAll("[^A-Za-z]", ""); + if (cleanString.length() >= 2) { + if (!taken.contains((char)(cleanString.charAt(1)|32))) { + if (!banned.contains((char)(cleanString.charAt(1)|32))) { + if (fm.charWidth('A') <= 2*fm.charWidth(cleanString.charAt(1))) { + jmi.setMnemonic(cleanString.charAt(1)); + taken.add((char)(cleanString.charAt(1)|32)); + continue algorithmicAssaignment; + } + } + } + } + + // METHOD 5: charComparator. + w = cleanString.toCharArray(); + word = new Character[w.length]; + for (int i = 0; i < w.length; i++) { + word[i] = new Character(w[i]); + } + Arrays.sort(word, charComparator); // sorts in increasing order + for (char mnem : word) { + 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); + taken.add(Character.toLowerCase(mnem)); + continue algorithmicAssaignment; + } + + // METHOD 6: Digits + for (char digit : jmi.getText().replaceAll("[^0-9]", "").toCharArray()) { + if (taken.contains(digit)) continue; + jmi.setMnemonic(KeyEvent.VK_0 + (digit - '0')); + taken.add(digit); + continue algorithmicAssaignment; + } + } + + // Finally, RECURSION. + for (JMenuItem jmi : menu) { + if (jmi instanceof JMenu) { + JMenu jm = (JMenu) jmi; + JMenuItem[] items = new JMenuItem[jm.getItemCount()]; + for (int i = 0; i < items.length; i++) { + items[i] = jm.getItem(i); + } + setMenuMnemonics(items); + } + } + } + + /** + * As setMenuMnemonics(JMenuItem...). + */ + public static void setMenuMnemonics(JMenuBar menubar) { + JMenuItem[] items = new JMenuItem[menubar.getMenuCount()]; + for (int i = 0; i < items.length; i++) { + items[i] = menubar.getMenu(i); + } + setMenuMnemonics(items); + } static public JCheckBoxMenuItem newJCheckBoxMenuItem(String title, int what) { JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(title); @@ -120,7 +336,6 @@ public class Toolkit { return menuItem; } - static public void addDisabledItem(JMenu menu, String title) { JMenuItem item = new JMenuItem(title); item.setEnabled(false); diff --git a/app/src/processing/app/contrib/ContributionPanel.java b/app/src/processing/app/contrib/ContributionPanel.java index 09ba24faf..22a865f72 100644 --- a/app/src/processing/app/contrib/ContributionPanel.java +++ b/app/src/processing/app/contrib/ContributionPanel.java @@ -146,6 +146,8 @@ class ContributionPanel extends JPanel { } } }); + openFolder.setMnemonic(KeyEvent.VK_O); + //Toolkit.setMenuMnemonics; setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); @@ -657,4 +659,4 @@ class ContributionPanel extends JPanel { } } } -} \ No newline at end of file +} From 6826aa74683163466d9a5ce6fd963d149ebd2670 Mon Sep 17 00:00:00 2001 From: GKFX Date: Sat, 1 Mar 2014 13:40:13 +0000 Subject: [PATCH 02/10] Finalize #51 fix --- app/src/processing/app/Toolkit.java | 75 ++++++++++++++++------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 96f3ad570..08082c63a 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -48,6 +48,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.regex.Pattern; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; @@ -116,6 +117,19 @@ public class Toolkit { return menuItem; } + static public JCheckBoxMenuItem newJCheckBoxMenuItem(String title, int what) { + JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(title); + int modifiers = awtToolkit.getMenuShortcutKeyMask(); + menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers)); + return menuItem; + } + + static public void addDisabledItem(JMenu menu, String title) { + JMenuItem item = new JMenuItem(title); + item.setEnabled(false); + menu.add(item); + } + /** * Removes all mnemonics, then sets a mnemonic for each menu and menu item * recursively by these rules: @@ -147,6 +161,8 @@ public class Toolkit { * No letter by an underscore will be assigned. * Disabled on Mac, per Apple guidelines. * menu 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. * @param font @@ -156,11 +172,11 @@ public class Toolkit { if (Base.isMacOS()) return; if (menu.length == 0) return; - // This list is the contents of http://techbase.kde.org/Projects/Usability/HIG/ + // This list is (mostly) the contents of http://techbase.kde.org/Projects/Usability/HIG/ // Keyboard_Accelerators, made lowercase, with nothing but letters left except // for ampersands before mnemonics and ".+" for changable text. (They are regexs.) // Note that every ampersand MUST be followed by a lowercase ASCII letter. - final String[] kdePreDefs = { "&file", "&new", "&open", "open&recent", "&save", + 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&", "©", "&paste", "&delete", "select&all", @@ -173,40 +189,43 @@ public class Toolkit { "&forward", "&gotopage", "&bookmarks", "&addbookmark", "bookmark&tabsasfolder", "&editbookmarks", "&newbookmarksfolder", "&tools", "&settings", "&toolbars", "configure&shortcuts", "configuretool&bars", "&configure*", "&help", ".+&handbook", - "&whatsthis", "report&bug", "&about[^k].*", "about&kde" }; + "&whatsthis", "report&bug", "&aboutprocessing", "about&kde" }; + 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]"); final FontMetrics fm = menu[0].getFontMetrics(menu[0].getFont()); final Comparator charComparator = new Comparator() { + char[] baddies = "qypgjaeiouQYPGJAEIOU".toCharArray(); public int compare(Character ch1, Character ch2) { // Descriminates against decenders 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 : "qypgjaeiouQYPGJAEIOU".toCharArray()) { + for (char bad : baddies) { if (bad == ch1) w1 *= 0.66; if (bad == ch2) w2 *= 0.66; } return (int)Math.signum(w2 - w1); } }; - // taken holds only [a-z], not uppercase. + // taken holds only [0-9a-z], not uppercase. // Prevents uppercase letters != lowercase letters, so // "Save" and "Save As" aren't both given 'a'. final List taken = new ArrayList(menu.length); char firstChar; - char[] w; // temp char array - Character[] word; - boolean foundYet = false; + char[] cleanChars; + Character[] cleanCharas; // METHOD 1: attempt to assign KDE defaults. for (JMenuItem jmi : menu) { if (jmi == null) continue; jmi.setMnemonic(0); // Reset. - for (String kdePreDef : kdePreDefs) { - if (jmi.getText().toLowerCase().replaceAll("[^a-z]","").matches(kdePreDef.replace("&",""))) { - // mnem is lowercase: might be best to make uppercase if neccessary. - char mnem = kdePreDef.charAt(1+kdePreDef.indexOf("&")); - jmi.setMnemonic(jmi.getText().indexOf(Character.toString(mnem).toUpperCase()) < 0 ? - mnem : (char)(mnem-32)); + for (int i = 0; i < kdePreDefStrs.length; i++) { + String cleanName = nonAAlpha.matcher(jmi.getText()).replaceAll("").toLowerCase(); + if (kdePreDefPats[i].matcher(cleanName).matches()) { + char mnem = kdePreDefStrs[i].charAt(1+kdePreDefStrs[i].indexOf("&")); + jmi.setMnemonic(mnem); taken.add(mnem); break; } @@ -267,7 +286,7 @@ public class Toolkit { } // METHOD 4: Second ASCII letter. - cleanString = cleanString.replaceAll("[^A-Za-z]", ""); + cleanString = nonAAlpha.matcher(jmi.getText()).replaceAll(""); if (cleanString.length() >= 2) { if (!taken.contains((char)(cleanString.charAt(1)|32))) { if (!banned.contains((char)(cleanString.charAt(1)|32))) { @@ -281,13 +300,13 @@ public class Toolkit { } // METHOD 5: charComparator. - w = cleanString.toCharArray(); - word = new Character[w.length]; - for (int i = 0; i < w.length; i++) { - word[i] = new Character(w[i]); + cleanChars = cleanString.toCharArray(); + cleanCharas = new Character[cleanChars.length]; + for (int i = 0; i < cleanChars.length; i++) { + cleanCharas[i] = new Character(cleanChars[i]); } - Arrays.sort(word, charComparator); // sorts in increasing order - for (char mnem : word) { + Arrays.sort(cleanCharas, charComparator); // sorts in increasing order + 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] @@ -299,6 +318,7 @@ public class Toolkit { // METHOD 6: Digits 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')); taken.add(digit); continue algorithmicAssaignment; @@ -329,19 +349,6 @@ public class Toolkit { setMenuMnemonics(items); } - static public JCheckBoxMenuItem newJCheckBoxMenuItem(String title, int what) { - JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(title); - int modifiers = awtToolkit.getMenuShortcutKeyMask(); - menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers)); - return menuItem; - } - - static public void addDisabledItem(JMenu menu, String title) { - JMenuItem item = new JMenuItem(title); - item.setEnabled(false); - menu.add(item); - } - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . From bf990a0d6d5a69953ef10bccfe756f61d39e34e9 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Mon, 31 Mar 2014 16:53:49 +0100 Subject: [PATCH 03/10] Update Editor.java Null-check. --- app/src/processing/app/Editor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 5d5d12144..9d7772083 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -876,8 +876,9 @@ public abstract class Editor extends JFrame implements RunnerListener { sketchMenu.add(mi); } - if (runItems.length != 0) - sketchMenu.addSeparator(); + if (runItems != null) + if (runItems.length != 0) + sketchMenu.addSeparator(); sketchMenu.add(mode.getImportMenu()); From 278d4fd24dcdcb1a5094d54f3e50ce33c883b791 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Mon, 31 Mar 2014 16:55:24 +0100 Subject: [PATCH 04/10] Update Toolkit.java Spacing as requested --- app/src/processing/app/Toolkit.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 08082c63a..f3552d7b6 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -117,6 +117,7 @@ public class Toolkit { return menuItem; } + static public JCheckBoxMenuItem newJCheckBoxMenuItem(String title, int what) { JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(title); int modifiers = awtToolkit.getMenuShortcutKeyMask(); @@ -124,6 +125,7 @@ public class Toolkit { return menuItem; } + static public void addDisabledItem(JMenu menu, String title) { JMenuItem item = new JMenuItem(title); item.setEnabled(false); @@ -338,6 +340,7 @@ public class Toolkit { } } + /** * As setMenuMnemonics(JMenuItem...). */ From fff8d0e0571398bd119b11f14ec0d5c37b661e99 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Wed, 2 Apr 2014 17:16:31 +0100 Subject: [PATCH 05/10] Update Toolkit.java Javadoc bug --- app/src/processing/app/Toolkit.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index f3552d7b6..3dd7cccc3 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -167,8 +167,6 @@ public class Toolkit { * 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. - * @param font - * A font for rendering character widths. */ public static void setMenuMnemonics(JMenuItem... menu) { if (Base.isMacOS()) return; From 1c591fe121c5e04b33eddea308f00cec1ef5647b Mon Sep 17 00:00:00 2001 From: George Bateman Date: Sun, 13 Apr 2014 11:42:36 +0100 Subject: [PATCH 06/10] Menu mnemonic bug fix I just found out that jmi.getText() can be null, so I added null-checking. --- app/src/processing/app/Toolkit.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 3dd7cccc3..5688bfd9e 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -220,6 +220,7 @@ public class Toolkit { // METHOD 1: attempt to assign KDE defaults. for (JMenuItem jmi : menu) { if (jmi == null) continue; + if (jmi.getText() == null) continue; jmi.setMnemonic(0); // Reset. for (int i = 0; i < kdePreDefStrs.length; i++) { String cleanName = nonAAlpha.matcher(jmi.getText()).replaceAll("").toLowerCase(); @@ -236,6 +237,7 @@ public class Toolkit { algorithmicAssaignment: for (JMenuItem jmi : menu) { if (jmi == null) continue; + if (jmi.getText() == null) continue; if (jmi.getMnemonic() != 0) continue; // Already assigned. // The string can't be made lower-case as that would spoil From 3b8d9f328c7a3cb12620045c50ce3d7e85fcd55f Mon Sep 17 00:00:00 2001 From: George Bateman Date: Sun, 24 Aug 2014 14:14:46 +0100 Subject: [PATCH 07/10] Menu mnemonics merge Merge menu mnemonics back with current code and integrate with PDE-X. --- app/src/processing/app/Editor.java | 41 ++++++------ app/src/processing/app/EditorHeader.java | 2 + app/src/processing/app/Toolkit.java | 63 ++++++++++++------- .../mode/experimental/DebugEditor.java | 35 ++++++----- 4 files changed, 81 insertions(+), 60 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index c05abbf2e..a6b2bb977 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -393,7 +393,6 @@ public abstract class Editor extends JFrame implements RunnerListener { public void actionPerformed(ActionEvent e) { if (!sketch.isModified()) { base.changeMode(m); - } else { Base.showWarning("Save", "Please save the sketch before changing the mode.", @@ -428,6 +427,8 @@ public abstract class Editor extends JFrame implements RunnerListener { } }); modeMenu.add(addLib); + + Toolkit.setMenuMnemonics(modeMenu); } @@ -2825,6 +2826,8 @@ public abstract class Editor extends JFrame implements RunnerListener { referenceItem; public TextAreaPopup() { + JMenuItem item; + cutItem = new JMenuItem(Language.text("menu.edit.cut")); cutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -2849,47 +2852,47 @@ public abstract class Editor extends JFrame implements RunnerListener { }); this.add(discourseItem); - pasteItem = new JMenuItem(Language.text("menu.edit.paste")); - pasteItem.addActionListener(new ActionListener() { + item = new JMenuItem(Language.text("menu.edit.paste")); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handlePaste(); } }); - this.add(pasteItem); + this.add(item); - selectAllItem = new JMenuItem(Language.text("menu.edit.select_all")); - selectAllItem.addActionListener(new ActionListener() { + item = new JMenuItem(Language.text("menu.edit.select_all")); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleSelectAll(); } }); - this.add(selectAllItem); + this.add(item); this.addSeparator(); - commUncommItem = new JMenuItem(Language.text("menu.edit.comment_uncomment")); - commUncommItem.addActionListener(new ActionListener() { + item = new JMenuItem(Language.text("menu.edit.comment_uncomment")); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleCommentUncomment(); } }); - this.add(commUncommItem); + this.add(item); - incIndItem = new JMenuItem("\u2192 " + Language.text("menu.edit.increase_indent")); - incIndItem.addActionListener(new ActionListener() { + item = new JMenuItem("\u2192 " + Language.text("menu.edit.increase_indent")); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleIndentOutdent(true); } }); - this.add(incIndItem); + this.add(item); - decIndItem = new JMenuItem("\u2190 "+Language.text("menu.edit.decrease_indent")); - decIndItem.addActionListener(new ActionListener() { + item = new JMenuItem("\u2190 " + Language.text("menu.edit.decrease_indent")); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleIndentOutdent(false); } }); - this.add(decIndItem); + this.add(item); this.addSeparator(); @@ -2900,10 +2903,8 @@ public abstract class Editor extends JFrame implements RunnerListener { } }); this.add(referenceItem); - - Toolkit.setMenuMnemonics(cutItem, copyItem, discourseItem, - pasteItem, selectAllItem, commUncommItem, incIndItem, - decIndItem, referenceItem); + + Toolkit.setMenuMnemonics(this); } // if no text is selected, disable copy and cut menu items diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java index 671095f14..58342e464 100644 --- a/app/src/processing/app/EditorHeader.java +++ b/app/src/processing/app/EditorHeader.java @@ -592,6 +592,8 @@ public class EditorHeader extends JComponent { menu.add(item); } } + + Toolkit.setMenuMnemonics(menu); } diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 80f245af8..972aed034 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -21,6 +21,7 @@ package processing.app; +import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.FontFormatException; @@ -57,6 +58,7 @@ import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; import javax.swing.JRootPane; import javax.swing.KeyStroke; @@ -145,7 +147,7 @@ public class Toolkit { * that is not taken. This is to try to be relevant, by using a letter well-associated * with the command. (MS guidelines) *
  • Ditto, but with lowercase.
  • - *
  • Next, it tries the second ASCII character, if its width >= half the width of + *
  • Next, it tries the second ASCII character, if its width >= half the width of * 'A'.
  • *
  • 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. @@ -199,10 +201,10 @@ public class Toolkit { final Pattern nonAAlpha = Pattern.compile("[^A-Za-z]"); FontMetrics fmTmp = null; for (JMenuItem m : menu) { - if (m != null) fmTmp = m.getFontMetrics(menu[0].getFont()); + if (m != null) fmTmp = m.getFontMetrics(m.getFont()); } - if (fmTmp == null) return; // All null menuitems. - final FontMetrics fm = fmTmp; + if (fmTmp == null) return; // All null menuitems; comparator would fail. + final FontMetrics fm = fmTmp; // Hack for accessing variable in comparator. final Comparator charComparator = new Comparator() { char[] baddies = "qypgjaeiouQYPGJAEIOU".toCharArray(); @@ -231,8 +233,9 @@ public class Toolkit { if (jmi.getText() == null) continue; jmi.setMnemonic(0); // Reset. for (int i = 0; i < kdePreDefStrs.length; i++) { - String cleanName = nonAAlpha.matcher(jmi.getText()).replaceAll("").toLowerCase(); - if (kdePreDefPats[i].matcher(cleanName).matches()) { + // To ASCII lowercase letters. + String lASCIIName = nonAAlpha.matcher(jmi.getText()).replaceAll("").toLowerCase(); + if (kdePreDefPats[i].matcher(lASCIIName).matches()) { char mnem = kdePreDefStrs[i].charAt(1+kdePreDefStrs[i].indexOf("&")); jmi.setMnemonic(mnem); taken.add(mnem); @@ -242,7 +245,7 @@ public class Toolkit { } // Where KDE defaults fail, use an algorithm. - algorithmicAssaignment: + algorithmicAssignment: for (JMenuItem jmi : menu) { if (jmi == null) continue; if (jmi.getText() == null) continue; @@ -278,7 +281,7 @@ public class Toolkit { if ('A' <= firstChar && firstChar <= 'Z') { jmi.setMnemonic(firstChar); taken.add((char)(firstChar | 32)); // tolowercase - continue algorithmicAssaignment; + continue algorithmicAssignment; } } @@ -291,25 +294,24 @@ public class Toolkit { if ('a' <= firstChar && firstChar <= 'z') { jmi.setMnemonic(firstChar); taken.add(firstChar); // is lowercase - continue algorithmicAssaignment; + continue algorithmicAssignment; } } - // METHOD 4: Second ASCII letter. + // METHOD 4: Second wide-enough ASCII letter. cleanString = nonAAlpha.matcher(jmi.getText()).replaceAll(""); if (cleanString.length() >= 2) { - if (!taken.contains((char)(cleanString.charAt(1)|32))) { - if (!banned.contains((char)(cleanString.charAt(1)|32))) { - if (fm.charWidth('A') <= 2*fm.charWidth(cleanString.charAt(1))) { - jmi.setMnemonic(cleanString.charAt(1)); - taken.add((char)(cleanString.charAt(1)|32)); - continue algorithmicAssaignment; - } - } - } + 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); + taken.add((char)(ascii2nd|32)); + continue algorithmicAssignment; + } } - // METHOD 5: charComparator. + // METHOD 5: charComparator over all ASCII letters. cleanChars = cleanString.toCharArray(); cleanCharas = new Character[cleanChars.length]; for (int i = 0; i < cleanChars.length; i++) { @@ -322,16 +324,16 @@ public class Toolkit { // NB: setMnemonic(char) doesn't want [^A-Za-z] jmi.setMnemonic(mnem); taken.add(Character.toLowerCase(mnem)); - continue algorithmicAssaignment; + continue algorithmicAssignment; } - // METHOD 6: Digits + // 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')); + jmi.setMnemonic(KeyEvent.VK_0 + digit - '0'); taken.add(digit); - continue algorithmicAssaignment; + continue algorithmicAssignment; } } @@ -359,6 +361,19 @@ public class Toolkit { } setMenuMnemonics(items); } + + + /** + * As setMenuMnemonics(JMenuItem...). + */ + public static void setMenuMnemonics(JPopupMenu menu) { + ArrayList items = new ArrayList(); + + for (Component c : menu.getComponents()) { + if (c instanceof JMenuItem) items.add((JMenuItem)c); + } + setMenuMnemonics(items.toArray(new JMenuItem[items.size()])); + } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 861806ada..e11c3271e 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -247,6 +247,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { // } // }); + Toolkit.setMenuMnemonics(ta.getRightClickPopup()); + // load settings from theme.txt ExperimentalMode theme = dmode; breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor); @@ -380,25 +382,26 @@ public class DebugEditor extends JavaEditor implements ActionListener { * For analytics purposes only. */ private void writeErrorsToFile(){ - if (errorCheckerService.tempErrorLog.size() == 0) - return; - try { - System.out.println("Writing errors"); - StringBuffer sbuff = new StringBuffer(); + if (errorCheckerService.tempErrorLog.size() == 0) return; + + try { + System.out.println("Writing errors"); + StringBuffer sbuff = new StringBuffer(); sbuff.append("Sketch: " + getSketch().getFolder() + ", " + new java.sql.Timestamp(new java.util.Date().getTime()) - + "\nComma in error msg is substituted with ^ symbol\nFor separating arguments in error args | symbol is used\n"); + + "\nComma in error msg is substituted with ^ symbol\nFor separating arguments in error args | symbol is used\n"); sbuff.append("ERROR TYPE, ERROR ARGS, ERROR MSG\n"); - for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { - IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); - if(ip != null){ - sbuff.append(ErrorMessageSimplifier.getIDName(ip.getID())); - sbuff.append(','); - sbuff.append("{"); - for (int i = 0; i < ip.getArguments().length; i++) { - sbuff.append(ip.getArguments()[i]); - if(i < ip.getArguments().length - 1) - sbuff.append("| "); + + for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { + IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); + if (ip != null) { + sbuff.append(ErrorMessageSimplifier.getIDName(ip.getID())); + sbuff.append(','); + sbuff.append("{"); + for (int i = 0; i < ip.getArguments().length; i++) { + sbuff.append(ip.getArguments()[i]); + if (i < ip.getArguments().length - 1) + sbuff.append("| "); } sbuff.append("}"); sbuff.append(','); From 35477abca92a78bf9ce3ffc0b487aac238ae9bca Mon Sep 17 00:00:00 2001 From: George Bateman Date: Mon, 25 Aug 2014 16:59:00 +0100 Subject: [PATCH 08/10] Finalise menu mnemonics Added Toolkit.setMenuMnemsInside(); removed Editor.resetMenuMnemonics(); added mnemonics to sketches in Sketch menu. --- app/src/processing/app/Editor.java | 23 +++++++---------------- app/src/processing/app/Toolkit.java | 21 +++++++++++++-------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index a6b2bb977..6f7fea8f0 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -65,8 +65,6 @@ public abstract class Editor extends JFrame implements RunnerListener { private PageFormat pageFormat; private PrinterJob printerJob; - // Used to reset mnemonics. - private JMenuBar menubar; // File and sketch menus for re-inserting items private JMenu fileMenu; // private JMenuItem saveMenuItem; @@ -147,9 +145,11 @@ public abstract class Editor extends JFrame implements RunnerListener { // fileMenu.insert(base.getSketchbookMenu(), 2); fileMenu.insert(base.getRecentMenu(), 2); // fileMenu.insert(mode.getExamplesMenu(), 3); + Toolkit.setMenuMnemsInside(fileMenu); + sketchMenu.insert(mode.getImportMenu(), 4); + Toolkit.setMenuMnemsInside(sketchMenu); mode.insertToolbarRecentMenu(); - resetMenuMnemonics(); } // added for 1.0.5 @@ -428,7 +428,7 @@ public abstract class Editor extends JFrame implements RunnerListener { }); modeMenu.add(addLib); - Toolkit.setMenuMnemonics(modeMenu); + Toolkit.setMenuMnemsInside(modeMenu); } @@ -547,7 +547,7 @@ public abstract class Editor extends JFrame implements RunnerListener { protected void buildMenuBar() { - menubar = new JMenuBar(); + JMenuBar menubar = new JMenuBar(); fileMenu = buildFileMenu(); menubar.add(fileMenu); menubar.add(buildEditMenu()); @@ -576,17 +576,8 @@ public abstract class Editor extends JFrame implements RunnerListener { // } menubar.add(buildHelpMenu()); - resetMenuMnemonics(); - setJMenuBar(menubar); - } - - - /** - * The reason for this is to avoid conflicting mnemonics. The code won't work properly - * if you run it on little bits at a time. - */ - public void resetMenuMnemonics() { Toolkit.setMenuMnemonics(menubar); + setJMenuBar(menubar); } @@ -964,7 +955,6 @@ public abstract class Editor extends JFrame implements RunnerListener { // Action listener to bring the appropriate sketch in front item.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { editor.setState(Frame.NORMAL); @@ -974,6 +964,7 @@ public abstract class Editor extends JFrame implements RunnerListener { }); sketchMenu.add(item); menuList.add(item); + Toolkit.setMenuMnemsInside(sketchMenu); } } diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 972aed034..3defe34f6 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -339,14 +339,7 @@ public class Toolkit { // Finally, RECURSION. for (JMenuItem jmi : menu) { - if (jmi instanceof JMenu) { - JMenu jm = (JMenu) jmi; - JMenuItem[] items = new JMenuItem[jm.getItemCount()]; - for (int i = 0; i < items.length; i++) { - items[i] = jm.getItem(i); - } - setMenuMnemonics(items); - } + if (jmi instanceof JMenu) setMenuMnemsInside((JMenu) jmi); } } @@ -376,6 +369,18 @@ public class Toolkit { } + /** + * Calls setMenuMnemonics(JMenuItem...) on the sub-elements only. + */ + public static void setMenuMnemsInside(JMenu menu) { + JMenuItem[] items = new JMenuItem[menu.getItemCount()]; + for (int i = 0; i < items.length; i++) { + items[i] = menu.getItem(i); + } + setMenuMnemonics(items); + } + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . From 1013bc37118c3f5f0dfeaac77fd69a90712b9306 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 18 Nov 2014 18:24:19 +0000 Subject: [PATCH 09/10] Fix tiny German menumnemonics bug. --- app/src/processing/app/Toolkit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 0d7f98d7d..0cf8f0a0f 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -193,7 +193,7 @@ public class Toolkit { "&forward", "&gotopage", "&bookmarks", "&addbookmark", "bookmark&tabsasfolder", "&editbookmarks", "&newbookmarksfolder", "&tools", "&settings", "&toolbars", "configure&shortcuts", "configuretool&bars", "&configure*", "&help", ".+&handbook", - "&whatsthis", "report&bug", "&aboutprocessing", "about&kde" }; + "&whatsthis", "report&bug", "&aboutprocessing", "about&kde", "&beenden" }; Pattern[] kdePreDefPats = new Pattern[kdePreDefStrs.length]; for (int i = 0; i < kdePreDefStrs.length; i++) kdePreDefPats[i] = Pattern.compile(kdePreDefStrs[i].replace("&","")); From 6cdd3f6a5e77717e280fae2a33b25a672d533bd5 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 18 Nov 2014 19:24:16 +0000 Subject: [PATCH 10/10] Translate cut and copy in the edit menu. Also condense some code. --- app/src/processing/app/Editor.java | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 2e89379d1..81426c182 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -733,11 +733,11 @@ public abstract class Editor extends JFrame implements RunnerListener { menu.addSeparator(); - cutItems = Toolkit.newJMenuItem("Cut", 'X'); + cutItems = Toolkit.newJMenuItem(Language.text("menu.edit.cut"), 'X'); cutItems.addActionListener(cutAction = new CutAction()); menu.add(cutItems); - copyItems = Toolkit.newJMenuItem("Copy", 'C'); + copyItems = Toolkit.newJMenuItem(Language.text("menu.edit.copy"), 'C'); copyItems.addActionListener(copyAction = new CopyAction()); menu.add(copyItems); @@ -1286,7 +1286,7 @@ public abstract class Editor extends JFrame implements RunnerListener { class CutAction extends AbstractAction { public CutAction() { - super("Cut"); + super(Language.text("menu.edit.cut")); this.setEnabled(false); } @@ -1296,11 +1296,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } public void updateCutState() { - if (canCut()) { - cutItems.setEnabled(true); - } else { - cutItems.setEnabled(false); - } + cutItems.setEnabled(canCut()); } public boolean canCut() { @@ -1310,7 +1306,7 @@ public abstract class Editor extends JFrame implements RunnerListener { class CopyAction extends AbstractAction { public CopyAction() { - super("Copy"); + super(Language.text("menu.edit.copy")); this.setEnabled(false); } @@ -1319,11 +1315,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } public void updateCopyState() { - if (canCopy()) { - copyItems.setEnabled(true); - } else { - copyItems.setEnabled(false); - } + copyItems.setEnabled(canCopy()); } public boolean canCopy() {