QJCC homepage

biz.chitec.quarterback.util
Class Hotkeys

java.lang.Object
  extended bybiz.chitec.quarterback.util.Hotkeys

public class Hotkeys
extends java.lang.Object

Low-level hotkey tool.

Knows how to create hotkeys for lists of strings. Normally, these strings will be button or menu labels or something similar which is collected outside Hotkeys (see biz.chitec.quarterback.HotkeyManager). Through the getHotkeys() method, a list of such Strings is given to the Hotkeys class, which will return a list of same size containing the Hotkeys for this bundle of Strings.

Hotkeys uses a recursive depth search with backtracking over all given strings to find an assignment of hotkeys to the given strings so that each one has its unique key. If this is not possible, a second search pass will find a solution where at least some strings get a hotkey. For each string, hotkey preference is: First look at beginnings of words, then at other characters, and search each group from left to right.

Recursive backtracking is notoriously slow. In this case, however, recursion depth isn't that deep (it cannot be deeper than 26, as there are no more hotkeys), and the number of possible alternatives on each level is not that big, either. So, search should normally be really fast. Nevertheless, Hotkeys features a cache which can be made persistent through the standard Java serialisation features. Just serialize the complete Hotkeys instance. To make the cache work properly, you have to pass a unique name for each String list you want to have hotkeys for. If the same name is given again and the MD5 sum over the strings is the same, Hotkeys simply returns the cached value.

Note: Hotkeys is not thread-safe. You should always call the methods in this class from the same thread.

Version:
$Id: fa113ef625efcf0e8fb12389438c8760c065d873 $
Author:
cantamen/Dirk Hillbrecht 2004
See Also:
HotkeyMaker

Nested Class Summary
private  class Hotkeys.FindCounter
          Counting sentinel to prevent search from going mad.
 
Field Summary
private  java.util.Map cache
          The cache
private static java.security.MessageDigest md
          Message digest for MD5 sum checking
private  java.util.ResourceBundle rb
          The resource bundle
 
Constructor Summary
Hotkeys()
          Initialize the instance and its cache.
 
Method Summary
private  java.util.List computeHotkeys(java.util.List entries, java.lang.String allowed)
          Internal computation method to be called if cache had no entry.
private  java.lang.String computeMD5(java.util.List entries, java.lang.String allowed)
          Compute an MD5 sum over a list of Strings and the allowed hotkeys Used internally to detect changes in cached input.
private  java.util.List computeRemainingHotkeys(java.util.List remaining, java.lang.String allowed, boolean relaxed, Hotkeys.FindCounter fc)
          Recursive hotkey search implementation Walks through first String in the list.
 java.lang.String getDefaultAllowedKeys()
          Return the default allowed hotkeys.
 java.util.List getHotkeys(java.lang.String element, java.util.List entries, java.lang.String allowed)
          Main method: Returns hotkeys list for given input.
private  java.util.ResourceBundle getRB()
          Load the instances own resource bundle if it is not already loaded.
private  java.lang.String reorderChars(java.lang.String original, java.lang.String allowed)
          Reorder the characters in a String so that leftmost is the best hotkey (and rightmost the worst) Starts with beginnings of words, then rests of words, both from left to right.
 java.lang.String shrinkAllowed(java.util.List hotkeys, java.lang.String allowed)
          Shrinks the allowed keys by the ones which are in the hotkeys list.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

md

private static transient java.security.MessageDigest md
Message digest for MD5 sum checking


cache

private java.util.Map cache
The cache


rb

private transient java.util.ResourceBundle rb
The resource bundle

Constructor Detail

Hotkeys

public Hotkeys()
Initialize the instance and its cache.

Method Detail

getRB

private java.util.ResourceBundle getRB()
Load the instances own resource bundle if it is not already loaded.


getDefaultAllowedKeys

public java.lang.String getDefaultAllowedKeys()
Return the default allowed hotkeys. The standard is "all lower case ASCII letters (a-z)".

Returns:
String containing all allowed hotkeys

reorderChars

private java.lang.String reorderChars(java.lang.String original,
                                      java.lang.String allowed)
Reorder the characters in a String so that leftmost is the best hotkey (and rightmost the worst) Starts with beginnings of words, then rests of words, both from left to right. Leaves out everything which is not hotkey-able (digits, whitespaces and so on)

Parameters:
original - A String to add a hotkey to
Returns:
The String's characters in new order

computeMD5

private java.lang.String computeMD5(java.util.List entries,
                                    java.lang.String allowed)
Compute an MD5 sum over a list of Strings and the allowed hotkeys Used internally to detect changes in cached input.

Parameters:
entries - List of Strings
allowed - String containing all allowed hotkeys
Returns:
String representing the MD5 sum over the input in Base64 encoding

getHotkeys

public java.util.List getHotkeys(java.lang.String element,
                                 java.util.List entries,
                                 java.lang.String allowed)
Main method: Returns hotkeys list for given input. Checks against cache and starts if nothing is found hotkeys computation. The returned List contains only String which are not longer than one character. If a String is empty, then Hotkeys was unable to assign a unique key to that string. It is guaranteed that the returned list is always exactly of the same size as the input list.

Parameters:
element - A unique name for the string list (used as cache key)
entries - The list of Strings
allowed - List of allowed hotkeys. If null, uses built-in default
Returns:
List of hotkeys as List of Strings. Always of same size as input.

shrinkAllowed

public java.lang.String shrinkAllowed(java.util.List hotkeys,
                                      java.lang.String allowed)
Shrinks the allowed keys by the ones which are in the hotkeys list. Needed if hotkes are assigned in several steps. Then, the hotkeys of one step must not be used in any of the subsequent steps. Therefore, after having created those hotkeys, they must be permanently removed from the allowed hotkeys list. Generally, this way is inferior compared to assigning all hotkeys globally. As the keys of the first step are lost for all the rest, assignments can become much harder and less simple.

Parameters:
hotkeys - List of hotkeys already in usage
allowed - String containing all allowed hotkeys
Returns:
String of allowed hotkeys which contains the given allowed keys minus the ones in the hotkeys list

computeHotkeys

private java.util.List computeHotkeys(java.util.List entries,
                                      java.lang.String allowed)
Internal computation method to be called if cache had no entry. Reorders characters to be "hotkey-friendly", then calls recursive computation method. If not enough hotkeys are allowed (less than number of Strings) or no complete hotkey assignment is possible, performs another recursive search, this time relaxed so that some Strings will not get a hotkey. It is unpredictable which Strings will be among the hotkeyless ones.

Parameters:
entries - List of Strings
allowed - String containing all allowed hotkeys
Returns:
List of hotkeys

computeRemainingHotkeys

private java.util.List computeRemainingHotkeys(java.util.List remaining,
                                               java.lang.String allowed,
                                               boolean relaxed,
                                               Hotkeys.FindCounter fc)
Recursive hotkey search implementation Walks through first String in the list. Tests from left to right whether current char is an allowed hotkey. If it is, take it and call myself recursively for rest of list. Continue on this level if rest of list returns null. If no hotkey can be found on this level, return either null or an empty String (relaxing mode).

Parameters:
remaining - List to search in, this recursion depth will only handle first entry
allowed - All allowed hotkeys
relaxed - Flag to indicate relaxed mode, in which it is allowed to be unable to find a hotkey
fc - global counter to restrict backtrace complexity
Returns:
List containing hotkey for this level and all below (which have been obtained recursively)

QJCC homepage