Package muntjac :: Package event :: Module shortcut_action
[hide private]
[frames] | no frames]

Source Code for Module muntjac.event.shortcut_action

  1  # Copyright (C) 2012 Vaadin Ltd.  
  2  # Copyright (C) 2012 Richard Lincoln 
  3  #  
  4  # Licensed under the Apache License, Version 2.0 (the "License");  
  5  # you may not use this file except in compliance with the License.  
  6  # You may obtain a copy of the License at  
  7  #  
  8  #     http://www.apache.org/licenses/LICENSE-2.0  
  9  #  
 10  # Unless required by applicable law or agreed to in writing, software  
 11  # distributed under the License is distributed on an "AS IS" BASIS,  
 12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
 13  # See the License for the specific language governing permissions and  
 14  # limitations under the License. 
 15   
 16  """A special type of C{Action}s used to create keyboard shortcuts.""" 
 17   
 18  import re 
 19   
 20  from muntjac.event.action import Action 
 21   
 22   
23 -class ShortcutAction(Action):
24 """Shortcuts are a special type of L{Action}s used to create keyboard 25 shortcuts. 26 27 The ShortcutAction is triggered when the user presses a given key in 28 combination with the (optional) given modifier keys. 29 30 ShortcutActions can be global (by attaching to the L{Window}), or attached 31 to different parts of the UI so that a specific shortcut is only valid in 32 part of the UI. For instance, one can attach shortcuts to a specific 33 L{Panel} - look for L{ComponentContainer}s implementing L{IHandler} or 34 L{INotifier}. 35 36 ShortcutActions have a caption that may be used to display the shortcut 37 visually. This allows the ShortcutAction to be used as a plain Action while 38 still reacting to a keyboard shortcut. Note that this functionality is not 39 very well supported yet, but it might still be a good idea to give a caption 40 to the shortcut. 41 42 @author: Vaadin Ltd. 43 @author: Richard Lincoln 44 """ 45 46 # Used in the caption shorthand notation to indicate the ALT modifier. 47 SHORTHAND_CHAR_ALT = '&' 48 49 # Used in the caption shorthand notation to indicate the SHIFT modifier. 50 SHORTHAND_CHAR_SHIFT = '_' 51 52 # Used in the caption shorthand notation to indicate the CTRL modifier. 53 SHORTHAND_CHAR_CTRL = '^' 54 55 # regex-quote (escape) the characters 56 _SHORTHAND_ALT = re.escape(SHORTHAND_CHAR_ALT) 57 _SHORTHAND_SHIFT = re.escape(SHORTHAND_CHAR_SHIFT) 58 _SHORTHAND_CTRL = re.escape(SHORTHAND_CHAR_CTRL) 59 60 # Used for replacing escaped chars, e.g && with & 61 _SHORTHAND_ESCAPE = re.compile(('(' + _SHORTHAND_ALT + '?)' 62 + _SHORTHAND_ALT + '|(' + _SHORTHAND_SHIFT + '?)' 63 + _SHORTHAND_SHIFT + '|(' + _SHORTHAND_CTRL + '?)' 64 + _SHORTHAND_CTRL)) 65 66 # Used for removing escaped chars, only leaving real shorthands 67 _SHORTHAND_REMOVE = re.compile(('([' + _SHORTHAND_ALT + '|' 68 + _SHORTHAND_SHIFT + '|' + _SHORTHAND_CTRL + '])\\1')) 69 70 # Mnemonic char, optionally followed by another, and optionally a third 71 _SHORTHANDS = re.compile(('(' + _SHORTHAND_ALT + '|' + _SHORTHAND_SHIFT 72 + '|' + _SHORTHAND_CTRL + ')(?!\\1)(?:(' + _SHORTHAND_ALT 73 + '|' + _SHORTHAND_SHIFT + '|' + _SHORTHAND_CTRL 74 + ')(?!\\1|\\2))?(?:(' + _SHORTHAND_ALT + '|' + _SHORTHAND_SHIFT 75 + '|' + _SHORTHAND_CTRL + ')(?!\\1|\\2|\\3))?.')) 76 77
78 - def __init__(self, *args):
79 """Creates a shortcut either using a shorthand notation to encode the 80 keycode a in the caption or one that reacts to the given L{KeyCode} and 81 (optionally) L{ModifierKey}s. 82 83 The shortcut might be shown in the UI (e.g context menu), in which case 84 the caption will be used. 85 86 Insert one or more modifier characters before the character to use as 87 keycode. E.g C{"&Save"} will make a shortcut responding to 88 ALT-S, C{"E^xit"} will respond to CTRL-X.<br/> 89 Multiple modifiers can be used, e.g C{"&^Delete"} will respond 90 to CTRL-ALT-D (the order of the modifier characters is not important). 91 92 The modifier characters will be removed from the caption. The modifier 93 character is be escaped by itself: two consecutive characters are turned 94 into the original character w/o the special meaning. E.g 95 C{"Save&&&close"} will respond to ALT-C, and the caption will 96 say "Save&close". 97 98 @param args: tuple of the form 99 - (caption, kc, m) 100 1. used when displaying the shortcut visually 101 2. KeyCode that the shortcut reacts to 102 3. optional modifier keys 103 - (caption, icon, kc, m) 104 1. used when displaying the shortcut visually 105 2. used when displaying the shortcut visually 106 3. KeyCode that the shortcut reacts to 107 4. optional modifier keys 108 - (shorthandCaption) 109 1. the caption in modifier shorthand 110 - (shorthandCaption, modifierKeys) 111 1. the caption in modifier shorthand 112 2. modifier keys 113 """ 114 self._keyCode = None 115 self._modifiers = tuple() 116 117 args = args 118 nargs = len(args) 119 if nargs == 1: 120 shorthandCaption, = args 121 ShortcutAction.__init__(self, shorthandCaption, None) 122 elif nargs == 2: 123 shorthandCaption, modifierKeys = args 124 125 # && -> & etc 126 super(ShortcutAction, self).__init__(self._SHORTHAND_ESCAPE.sub( 127 shorthandCaption, '$1$2$3')) 128 129 # replace escaped chars with something that won't 130 # accidentally match 131 shorthandCaption = self._SHORTHAND_REMOVE.sub( 132 shorthandCaption, '\u001A') 133 134 m = self._SHORTHANDS.search(shorthandCaption) # FIXME: check regex 135 if m is not None: 136 match = m.group() 137 138 # KeyCode from last char in match, uppercase 139 self._keyCode = m.group()[len(match) - 1].upper() 140 141 # Given modifiers override this indicated in the caption 142 if modifierKeys is not None: 143 self._modifiers = modifierKeys 144 else: 145 # Read modifiers from caption 146 mod = [None] * (len(match) - 1) 147 for i in range(len(mod)): 148 kc = match[i] 149 150 if kc == self.SHORTHAND_CHAR_ALT: 151 mod[i] = self.ModifierKey.ALT 152 153 elif kc == self.SHORTHAND_CHAR_CTRL: 154 mod[i] = self.ModifierKey.CTRL 155 156 elif kc == self.SHORTHAND_CHAR_SHIFT: 157 mod[i] = self.ModifierKey.SHIFT 158 159 self._modifiers = mod 160 else: 161 self._keyCode = -1 162 self._modifiers = modifierKeys 163 elif nargs == 3: 164 caption, kc, m = args 165 super(ShortcutAction, self).__init__(caption) 166 self._keyCode = kc 167 self._modifiers = m 168 elif nargs == 4: 169 caption, icon, kc, m = args 170 super(ShortcutAction, self).__init__(caption, icon) 171 self._keyCode = kc 172 self._modifiers = m 173 else: 174 raise ValueError, 'invalid number of arguments'
175 176
177 - def getKeyCode(self):
178 """Get the L{KeyCode} that this shortcut reacts to (in 179 combination with the L{ModifierKey}s). 180 181 @return: keycode for this shortcut 182 """ 183 return self._keyCode
184 185
186 - def getModifiers(self):
187 """Get the L{ModifierKey}s required for the shortcut to react. 188 189 @return: modifier keys for this shortcut 190 """ 191 return self._modifiers
192 193
194 -class KeyCode(object):
195 """Key codes that can be used for shortcuts""" 196 197 ENTER = 13 198 ESCAPE = 27 199 PAGE_UP = 33 200 PAGE_DOWN = 34 201 TAB = 9 202 ARROW_LEFT = 37 203 ARROW_UP = 38 204 ARROW_RIGHT = 39 205 ARROW_DOWN = 40 206 BACKSPACE = 8 207 DELETE = 46 208 INSERT = 45 209 END = 35 210 HOME = 36 211 F1 = 112 212 F2 = 113 213 F3 = 114 214 F4 = 115 215 F5 = 116 216 F6 = 117 217 F7 = 118 218 F8 = 119 219 F9 = 120 220 F10 = 121 221 F11 = 122 222 F12 = 123 223 A = 65 224 B = 66 225 C = 67 226 D = 68 227 E = 69 228 F = 70 229 G = 71 230 H = 72 231 I = 73 232 J = 74 233 K = 75 234 L = 76 235 M = 77 236 N = 78 237 O = 79 238 P = 80 239 Q = 81 240 R = 82 241 S = 83 242 T = 84 243 U = 85 244 V = 86 245 W = 87 246 X = 88 247 Y = 89 248 Z = 90 249 NUM0 = 48 250 NUM1 = 49 251 NUM2 = 50 252 NUM3 = 51 253 NUM4 = 52 254 NUM5 = 53 255 NUM6 = 54 256 NUM7 = 55 257 NUM8 = 56 258 NUM9 = 57 259 SPACEBAR = 32
260 261
262 -class ModifierKey(object):
263 """Modifier key constants""" 264 265 SHIFT = 16 266 CTRL = 17 267 ALT = 18 268 META = 91
269