Mercurial > hg > accesspd
view java/src/uk/ac/qmul/eecs/ccmi/gui/SpeechMenuFactory.java @ 0:78b7fc5391a2
first import, outcome of NIME 2014 hackaton
author | Fiore Martin <f.martin@qmul.ac.uk> |
---|---|
date | Tue, 08 Jul 2014 16:28:59 +0100 |
parents | |
children |
line wrap: on
line source
/* CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package uk.ac.qmul.eecs.ccmi.gui; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.text.MessageFormat; import java.util.ResourceBundle; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ComponentInputMap; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.KeyStroke; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import uk.ac.qmul.eecs.ccmi.sound.SoundEvent; import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory; /* * This class provides a version of JMenuItem, JCheckBox, and JMenu which emit an "error" sound when * they're disabled and the user tries to use it by an accelerator */ @SuppressWarnings("serial") class SpeechMenuFactory extends JMenu { /* implements the singleton pattern and keeps a static reference to the menuBar used by JMenuItems and JMenus */ public static JMenuBar getMenuBar(){ if(menuBar == null){ menuBar = new SpeechMenuBar(); } return menuBar; } public static JMenuItem getMenuItem(String text){ return new SpeechMenuItem(text); } public static JMenu getMenu(String text){ return new JMenu(text){ @Override public void menuSelectionChanged(boolean isIncluded){ super.menuSelectionChanged(isIncluded); if(isIncluded && !wasMouse){ String menuType = resources.getString("menufactory.menu"); if(getMenuBar().getComponentIndex(this) == -1){ menuType = resources.getString("menufactory.submenu"); }; NarratorFactory.getInstance().speak(getAccessibleContext().getAccessibleName()+ " "+ menuType); } wasMouse = false; } @Override public void processMouseEvent(MouseEvent e){ wasMouse = true; super.processMouseEvent(e); } private boolean wasMouse = false; }; } public static JCheckBoxMenuItem getJCheckBoxMenuItem(String text){ return new SpeechJCheckBoxMenuItem(text); } /* this action is called when the user strokes a disabled menu accelerator */ private static Action errorAction = new AbstractAction(){ @Override public void actionPerformed(ActionEvent e) { SoundFactory.getInstance().play(SoundEvent.ERROR); } }; private static class SpeechMenuBar extends JMenuBar{ SpeechMenuBar() { setInputMap(SpeechMenuBar.WHEN_IN_FOCUSED_WINDOW, new ComponentInputMap(this){ @Override public Object get(KeyStroke keyStroke){ if(keyStroke == null) return null; return super.get(keyStroke); } }); } @Override public void processKeyEvent(KeyEvent e, MenuElement[] path, MenuSelectionManager manager) { super.processKeyEvent(e,path,manager); if(e.getKeyCode() == KeyEvent.VK_ESCAPE){ NarratorFactory.getInstance().speak(resources.getString("menufactory.leaving")); } } } /* * this class implements a menu item which speaks out its label when * selected with the keyboard (mouse hover will have no effect) * it needs a reference to the menu bar it's in to implement a respond, with the error sound, to * the accelerator even when it's disabled (normally no listeners are called otherwise) * */ private static class SpeechMenuItem extends JMenuItem{ @Override public void processMouseEvent(MouseEvent e ){ wasMouse = true; super.processMouseEvent(e); } public SpeechMenuItem(String text){ super(text); /* bind ACCELERATOR with the error action */ getMenuBar().getActionMap().put(ACCELERATOR, errorAction); wasMouse = false; if(text.trim().endsWith("...")){ /* replace the ... in the accessible name with the voice version of it */ String accName = getAccessibleContext().getAccessibleName().replaceAll("...\\s*$", ""); getAccessibleContext().setAccessibleName(accName +" "+ resources.getString("menufactory.3dot")); } } @Override public void menuSelectionChanged(boolean isIncluded){ super.menuSelectionChanged(isIncluded); if(isIncluded && !wasMouse){ String disabled = isEnabled() ? "" : resources.getString("menufactory.disabled"); String accelerator = ""; if(getAccelerator() != null){ accelerator = resources.getString("menufactory.ctrl")+" "+ getAccelerator().toString().substring(getAccelerator().toString().lastIndexOf(' ')); } NarratorFactory.getInstance().speak(getAccessibleContext().getAccessibleName()+disabled+accelerator); } wasMouse = false; } @Override public void setEnabled(boolean b){ super.setEnabled(b); if(getAccelerator() == null) return; if(b == false){ /* if the menu item gets disabled, then set up an action in the menuBar to respond to * the accelerator key stroke, so that the user gets a feedback (error sound) * even though the listeners don't get called (as the menu item is disabled) */ getMenuBar().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(getAccelerator(), ACCELERATOR); }else{ getMenuBar().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(getAccelerator(), "none"); } } private boolean wasMouse; }; private static class SpeechJCheckBoxMenuItem extends JCheckBoxMenuItem { public SpeechJCheckBoxMenuItem(String text){ super(text); addItemListener(new ItemListener(){ @Override public void itemStateChanged(ItemEvent evt) { int stateChange = evt.getStateChange(); if(stateChange != ItemEvent.SELECTED && stateChange != ItemEvent.DESELECTED){ return; } if(!itemChangeMouseFlag){ NarratorFactory.getInstance().speak( MessageFormat.format( resources.getString(stateChange == ItemEvent.SELECTED ? "menufactory.selected" : "menufactory.unselected"), getAccessibleContext().getAccessibleName())); } itemChangeMouseFlag = false; } }); } @Override public void menuSelectionChanged(boolean isIncluded){ super.menuSelectionChanged(isIncluded); if(isIncluded && !selectionMouseFlag ){ NarratorFactory.getInstance().speak( MessageFormat.format( resources.getString(isSelected() ? "menufactory.selected" : "menufactory.unselected"), getAccessibleContext().getAccessibleName())); } selectionMouseFlag = false; } @Override public void processMouseEvent(MouseEvent e){ selectionMouseFlag = true; itemChangeMouseFlag = true; super.processMouseEvent(e); } private boolean selectionMouseFlag = false; private boolean itemChangeMouseFlag = false; } private static JMenuBar menuBar; private static ResourceBundle resources = ResourceBundle.getBundle(EditorFrame.class.getName()); private static final String ACCELERATOR = "accelerator"; }