Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>My assumption - <em>nothing special required to do, JOptionPane just does it</em> - was based on skimming BasicOptionPaneUI code and checking if the optionPane's audioActionMap is installed. </p> <p>The place where the audio is played is in the ui's propertyChangeListener on a change to its ancestor property:</p> <pre><code>if ("ancestor" == e.getPropertyName()) { JOptionPane op = (JOptionPane)e.getSource(); boolean isComingUp; // if the old value is null, then the JOptionPane is being // created since it didn't previously have an ancestor. if (e.getOldValue() == null) { isComingUp = true; } else { isComingUp = false; } // figure out what to do based on the message type switch (op.getMessageType()) { case JOptionPane.PLAIN_MESSAGE: if (isComingUp) { BasicLookAndFeel.playSound(optionPane, "OptionPane.informationSound"); } break; // all other message types handled as well } </code></pre> <p>the shared actionMap is installed (lazyly, so an optionPane must have been visible once)</p> <pre><code>assertTrue(UIManager.get("AuditoryCues.actionMap") instanceof ActionMap); ActionMap map = (ActionMap) UIManager.get("AuditoryCues.actionMap"); assertNotNull(map.get("OptionPane.errorSound")); </code></pre> <p>sounds enabled on OS (win 7) level and sound on hardware turned on (just for testing) ... WTF: but nothing happens (and assumption proven to be wrong ;-)</p> <p>Debug session (I hate it ... but occasionally ...) turns out that performing the audioAction doesn't happen, here are the methods involved : </p> <pre><code>static void playSound(JComponent c, Object actionKey) { LookAndFeel laf = UIManager.getLookAndFeel(); if (laf instanceof BasicLookAndFeel) { ActionMap map = c.getActionMap(); if (map != null) { Action audioAction = map.get(actionKey); if (audioAction != null) { // pass off firing the Action to a utility method // JW: we have an audioAction, so on to the next method ((BasicLookAndFeel)laf).playSound(audioAction); } } } } protected void playSound(Action audioAction) { if (audioAction != null) { Object[] audioStrings = (Object[]) UIManager.get("AuditoryCues.playList"); if (audioStrings != null) { // JW: here the action is performed ... except we don't reach this .... } } </code></pre> <p>That's rather astonishing, isn't it? After all, the action were created, so if there is no playlist, why would they have been created?</p> <p>And here comes the catch: the list used for creating the actions is a different list</p> <pre><code>// in BasicLookAndFeel protected ActionMap getAudioActionMap() { ActionMap audioActionMap = (ActionMap)UIManager.get( "AuditoryCues.actionMap"); if (audioActionMap == null) { // here it's named cueList Object[] acList = (Object[])UIManager.get("AuditoryCues.cueList"); } </code></pre> <p>and the reason that's a different list is ... to allow LAFs to customize the sounds that actually are to be played</p> <pre><code>// BasicLookAndFeel // *** Auditory Feedback "AuditoryCues.cueList", allAuditoryCues, // this key defines which of the various cues to render. // L&amp;Fs that want auditory feedback NEED to override playList. "AuditoryCues.playList", null, </code></pre> <p>Ooookaaayy .. so let's see what a concrete LAF is doing, f.i. Win:</p> <pre><code>// *** Auditory Feedback // this key defines which of the various cues to render // Overridden from BasicL&amp;F. This L&amp;F should play all sounds // all the time. The infrastructure decides what to play. // This is disabled until sound bugs can be resolved. "AuditoryCues.playList", null, // table.get("AuditoryCues.cueList"), </code></pre> <p>EOL.</p> <p>Not quite :-) This comment hints to what is doable:</p> <pre><code>Object[] cueList = (Object[]) UIManager.get("AuditoryCues.cueList"); UIManager.put("AuditoryCues.playList", cueList); </code></pre> <p>Which in fact does work for WindowsLAF (even respecting the OS sound schema and - most importantly - <em>not</em> playing if disabled), but not for any of the other core LAFs. </p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload