Module PidginScript
[hide private]
[frames] | no frames]

Source Code for Module PidginScript

  1  ''' 
  2  Defines a user interface for pidgin. 
  3   
  4  Keys registered 
  5   
  6  CapsLock-W: Reports status of all open conversations 
  7  CapsLock-S: Cycle focus between message history and compose area 
  8   
  9  Event announcements 
 10   
 11  (X) means optional announcement X based on type of widget 
 12  [X] means X always announced 
 13  <X> indicates continue announcements in X 
 14   
 15  on activate: ["chat with" username] 
 16  on focus: ["compose" or "history"] <active descendant change> 
 17  on message received: [text of message] 
 18     
 19  @var CONTAINER_PATH: path from frame to container with accessible elements 
 20  @type CONTAINER_PATH: integer 
 21  @var NUM_CHILDREN_IN_CHAT_WINDOW: to identify a chat window: assume that only 
 22    this acc will have 2 kids, and further assume that accessibles with similar 
 23    hierarchical placement will not. 
 24  @type NUM_CHILDREN_IN_CHAT_WINDOW: integer 
 25  @var MENU_BAR_PATH: path: from container to menu bar 
 26  @type MENU_BAR_PATH: integer 
 27  @var TAB_PATH: path from container to page tab list (contains conversations) 
 28  @type TAB_PATH: integer 
 29  @var HISTORY_PATH: path from a conversation tab to its history text panel 
 30  @type HISTORY_PATH: integer 
 31  @var COMPOSE_PATH: path from a conversation tab to its compose text panel 
 32  @type COMPOSE_PATH: integer 
 33  @var UNREAD_STATUS: Constant representing a conversation has an unread  
 34    message 
 35  @type UNREAD_STATUS: integer 
 36  @var TYPING_STATUS: Constant representing a chat partner is currently typing 
 37    in a conversation 
 38  @type TYPING_STATUS: integer 
 39  @var PAUSED_STATUS: Constant representing a chat partner is stoped typing 
 40    in a conversation 
 41  @type PAUSED_STATUS: integer 
 42  @var IDLE_STATUS: Constant representing a chat partner is idle in a  
 43    conversation 
 44  @type IDLE_STATUS: integer 
 45  @var OFFLINE_STATUS: Constant representing a chat partner is offline in a  
 46    conversation 
 47  @type OFFLINE_STATUS: integer 
 48  @var RED: Gtk color description of color red, as string 
 49  @type RED: string 
 50  @var GREEN: Gtk color description of color green, as string 
 51  @type GREEN: string 
 52  @var YELLOW: Gtk color description of color yellow, as string 
 53  @type YELLOW: string 
 54  @var LOGOUT_GREY: Gtk color description of grey, as string, used in logoff 
 55  @type LOGOUT_GREY: string 
 56  @var STATUS_MSG: List of strings describing the unread, typing, etc. status 
 57    of conversations sorted by their likely importance to the user 
 58  @type STATUS_MSG: list of string 
 59   
 60  @author: Brett Clippingdale 
 61  @author: Peter Parente 
 62  @organization: IBM Corporation 
 63  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 64  @license: The BSD License 
 65   
 66  All rights reserved. This program and the accompanying materials are made  
 67  available under the terms of the BSD license which accompanies 
 68  this distribution, and is available at 
 69  U{http://www.opensource.org/licenses/bsd-license.php} 
 70  ''' 
 71  from AccessEngine import AEConstants 
 72  from AccessEngine import AEState, AEScript, AccessEngineAPI 
 73  from AccessEngine.AEPor import AEPor 
 74  from Tools.i18n import _ 
 75   
 76  __uie__ = dict(kind='script', tier='pidgin') 
 77   
 78  # actual paths, derived using at-poke, assumed to be static.  YMMV. 
 79  # path: from frame to container with accessible elements    
 80  CONTAINER_PATH = 0 
 81  # to identify a chat window: assume that only this acc will have 2 kids, and 
 82  # further assume that accessibles with similar hierarchical placement will 
 83  # not.  Again, YMMV, so analyze carefully with AT-Poke and then verify. 
 84  NUM_CHILDREN_IN_CHAT_WINDOW = 2 
 85  # path: from container to page tab list (contains all conversations) 
 86  TAB_PATH = 1   
 87   
 88  # actual paths in Pidgin 1.5, derived using at-poke, assumed to be static 
 89  # if Pidgin 2, these will get different values in setPidginEnviron() 
 90  HISTORY_PATH = (0,0,0,0,0) # path: tab (a conversation) to history text panel 
 91  COMPOSE_PATH = (0,0,1,1,0,0,0) # path: tab to chat compose text panel 
 92   
 93  # pidgin colors, (eg. convo tab text color depends on typing/login status) 
 94  RED = "57311,16962,7710" # unread msg 
 95  GREEN = "18247,41120,17990" # active typing 
 96  YELLOW = "53713,38036,3084" # paused typing 
 97  GREY = "34438,33410,29298" # off-line 
 98  LOGOUT_GREY = "32639, 32639, 32639" # used in buddy list on logoff 
 99  # constants for status of conversations 
100  UNREAD_STATUS = 0 
101  TYPING_STATUS = 1 
102  PAUSED_STATUS = 2 
103  IDLE_STATUS = 3 
104  OFFLINE_STATUS = 4 
105  LOGIN_STATUS = 5 
106  LOGOUT_STATUS = 6 
107  STATUS_MSG = [_('unseen'), _('typing'), _('paused'), _('idle'), _('offline'), 
108                _('logged in'), _('logged out')]  
109   
110 -class PidginScriptState(AEScript.ScriptState):
111 ''' 112 Settings for Pidgin. 113 114 ReadBackground (bool): Read incoming messages when pidgin is in the background? 115 '''
116 - def init(self):
117 self.newBool('ReadBackground', False, _('Read background messages?'), 118 _('When checked, incoming messages will be read even when ' 119 'Pidgin is in the background.')) 120 self.newBool('BrailleBackground', False, _('Braille background messages?'), 121 _('When checked, incoming messages will be output to Braille ' 122 'device even when Pidgin is in the background.'))
123
124 - def getGroups(self):
125 g = self.newGroup() 126 g.append('ReadBackground') 127 g.append('BrailleBackground') 128 return g
129
130 -class PidginScript(AEScript.AEScript):
131 ''' 132 Provides hotkeys for switching between the message history and message 133 compose areas. Announces incoming messages and allows for review by entire 134 message. 135 136 Has initial support for announcing when buddies sign in and out and when the 137 status of a conversation changes. Written to work with both pidgin 1.5 and 2.0. 138 139 @ivar chat_compose_por: Reference to chat msg compose panel 140 @type chat_compose_por: L{AEPor} 141 @ivar chat_history_por: Reference to chat history panel 142 @type chat_history_por: L{AEPor} 143 @ivar last_convo: Reference to the last selected conversation tab 144 @type last_convo: L{AEPor} 145 @ivar initialized: have pidgin environment variables been initialized? 146 @type initialized: boolean 147 @ivar is_pidgin2: is user client Pidgin2 ? 148 @type is_pidgin2: boolean 149 @ivar is_history_focused: does chat history panel currently have focus? 150 @type is_history_focused: boolean 151 @ivar last_history_caret: track caret in history panel, read when on new line 152 @type last_history_caret: L{AEPor} 153 ''' 154 STATE = PidginScriptState 155
156 - def init(self):
157 ''' 158 Registers keyboard bindings that give status of conversation tabs (unread 159 message, active typing, paused typing) and drive focus back and forth 160 between chat composition text area and history text area. 161 ''' 162 163 # set an audio device as the default output 164 AccessEngineAPI.setScriptIdealOutput('audio')
165 166 ## register event handlers 167 ## events here are app-level, other Scripts will handle gnome-level events, 168 ## so only register events of interest here. 169 #AccessEngineAPI.registerTask(ActivatePidginWindow('pidgin read window')) 170 #AccessEngineAPI.registerTask(HandleFocusChange('pidgin read focus')) 171 #AccessEngineAPI.registerTask(HandleSelectorChange('pidgin read selector')) 172 #AccessEngineAPI.registerTask(HandleCaretChange('pidgin read caret')) 173 #AccessEngineAPI.registerTask(ReadIncoming('pidgin read incoming', all=True)) 174 ## not working for background events ??? 175 ##self.registerEventTask(HandlePropertyChange(focus=True, tier=True, 176 ## background=True)) 177 ## @note: not handling TableChange until certain Pidgin bugs fixed 178 ## if re-enabled, may want to uncomment debug code: last_por_inserted (global 179 ## variable) and code in handleCaretChange 180 ##self.registerEventTask(BuddySignOnOff(focus=True, tier=True, 181 ##background=True)) 182 183 ## register named tasks. Specify the task class name (see below) and a 184 ## description. These descriptions are dictionary keys and therefore 185 ## must be unique. Here, Pidgin is a prefix to help ensure uniqueness. 186 #AccessEngineAPI.registerTask(ToggleChatPanel('pidgin chat panel toggle')) 187 #AccessEngineAPI.registerTask(ConversationStatus('pidgin conversation status')) 188 189 ## get the Keyboard device and register modifiers. 190 #kbd = AccessEngineAPI.getInputDevice(None, 'keyboard') 191 #AccessEngineAPI.addInputModifiers(self, kbd, kbd.AEK_CAPS_LOCK) 192 193 ## register the keys and their associated commands, binding them using the 194 ## unique dictionary key we registered above. 195 ## Pass 3 element tuple. Need to capture keys as pressed though we only 196 ## handle them if all both modifiers pressed before the non-modifier. 197 #AccessEngineAPI.registerCommand(kbd, 'pidgin chat panel toggle', False, 198 #[kbd.AEK_CAPS_LOCK, kbd.AEK_S]) 199 #AccessEngineAPI.registerCommand(kbd, 'pidgin conversation status', False, 200 #[kbd.AEK_CAPS_LOCK, kbd.AEK_W]) 201 202 ## POR reference to chat composition text area 203 #self.chat_compose_por = AEPor() 204 ## POR reference to chat history text area 205 #self.chat_history_por = AEPor() 206 #self.last_convo = AEPor() 207 208 ## have pidgin environment variables been initialized? This must happen first 209 ## time that pidgin chat window is activated 210 #self.initialized = False 211 ## is user client Pidgin 2.0 instead of 1.5? 212 #self.is_pidgin2 = False 213 214 ## does chat history panel currently have focus 215 #self.is_history_focused = False 216 #self.last_history_caret = AEPor() 217 218 ## is there selection in the composition area? used to avoid announcing 219 ## deleted text when sending 220 #self.selection = False 221 222 ## may be used in case where, on sign-off, multiple inserts fire 223 ##debug, see handleRowInserted, handleCaretChange 224 ##last_row_inserted_por = None 225 226 #def getActivePageTabListPOR(self): 227 #''' 228 #Gets a Point of Regard to the page tab list in an active chat window. 229 230 #@return: Point of Regard to the page tab list in an active chat window, 231 #or None otherwise 232 #@rtype: L{AEPor} 233 #''' 234 #frame_por = AccessEngineAPI.getRootAcc() 235 #container_por = AccessEngineAPI.getAccFromPath(frame_por, CONTAINER_PATH) 236 ## is chat window active? 237 #if (AccessEngineAPI.hasAccState('active', frame_por) and 238 #AccessEngineAPI.getAccCount(container_por) == NUM_CHILDREN_IN_CHAT_WINDOW): 239 ## get 'page tab list' 240 #tab_list_por = AccessEngineAPI.getAccFromPath(container_por, TAB_PATH) 241 #if AccessEngineAPI.hasAccRole("page tab list", tab_list_por): 242 #return tab_list_por 243 ## in all other cases, return None 244 #return None 245 246 #def getTypingStatus(self, por): 247 #''' 248 #Gets current typing status on a given conversation L{AEPor}. 249 250 #@return: One of L{UNREAD_STATUS}, L{TYPING_STATUS}, L{PAUSED_STATUS}, 251 #L{IDLE_STATUS} that can be mapped to a message in L{STATUS_MSG} 252 #@rtype: integer 253 #''' 254 #value = self.getAccTextAttr("fg-color", por) 255 ## red: message typed, unread 256 #if value == RED: 257 #return UNREAD_STATUS 258 ## green: typing 259 #elif value == GREEN: 260 #return TYPING_STATUS 261 ## yellow: paused 262 #elif value == YELLOW: 263 #return PAUSED_STATUS 264 ## grey: offline 265 #elif value == GREY: 266 #return OFFLINE_STATUS 267 ## black: (no typing), and no fg-color value 268 #else: 269 #return IDLE_STATUS 270 271 #def setPidginVersion(self): 272 #''' 273 #Applies a heuristic to determine which Pidgin version is running locally. 274 #This is important because the the representation of the UI varies by local 275 #client, and in the case of a local Pidgin 2 it also varies by remote client. 276 #''' 277 #tab_list_por = self.getActivePageTabListPOR() 278 ## get selected conversation tab 279 #selected_tab_por = AccessEngineAPI.getFirstSelected(tab_list_por) 280 #self.chat_history_por = \ 281 #AccessEngineAPI.getAccFromPath(selected_tab_por, *HISTORY_PATH) 282 ## if this is a "filler" rather than a text area, must be Pidgin2 283 #if AccessEngineAPI.getAccRoleName(self.chat_history_por) == "filler": 284 #self.is_pidgin2 = True 285 #print "chat client is Pidgin beta 2 or higher" 286 #else: 287 #print "chat client is Pidgin 1.5 or lower" 288
289 - def getName(self):
290 ''' 291 @return: Human readable name of this L{AEScript <AEScript.AEScript>}. 292 @rtype: string 293 ''' 294 return _('Pidgin')
295 296 ## 297 ## Tasks executed by keys 298 ## 299 300 #class ToggleChatPanel(Task.InputTask): 301 #''' 302 #Toggles focus between chat composition and chat history panels. 303 #''' 304 ## each task class must implement an execute method which is called when 305 ## the associated key bindings (registered in init method, above) are pressed 306 #def execute(self, **kwargs): 307 ## determine which chat panel currently has focus. Specify which 308 ## ATSPI-defined property of interest (here, 'focused') and the POR to check 309 ## for that property 310 #tab_list_por = self.script.getActivePageTabListPOR() 311 #if tab_list_por is not None: 312 #if not self.script.is_history_focused: 313 ##change focus to chat history panel 314 #self.setAccFocus(self.script.chat_history_por) 315 #else: 316 ##change focus to chat compose panel 317 #self.setAccFocus(self.script.chat_compose_por) 318 #return True # allow triggering keystrokes to propagate (default) 319 320 #class ConversationStatus(Task.InputTask): 321 #''' 322 #Announces the status of the current conversations. Status for conversations 323 #is grouped by status type except for the foreground conversation which is 324 #always reported first. 325 #''' 326 #def execute(self, **kwargs): 327 #brailleout=[] 328 #tab_list_por = self.script.getActivePageTabListPOR() 329 ## is chat window active? otherwise, don't switch 330 #if tab_list_por is None: 331 #return True 332 333 ## stop prior speech 334 #self.stopNow() 335 336 ## get selected conversation tab 337 #selected_tab_por = self.getFirstSelected(tab_list_por) 338 339 #por = self.getFirstPeerAcc(selected_tab_por) 340 #l = [] 341 #while por is not None: 342 ## get the tab name and status value 343 #name = self.getAccName(por) 344 ## if acc not an artifact, process 345 #if name != '': 346 #value = self.script.getTypingStatus(por) 347 #print selected_tab_por 348 #if selected_tab_por == por: 349 #self.sayState(text=(name, STATUS_MSG[value]), template='%s %s,') 350 #brailleout.append('%s: %s, ' % (name, STATUS_MSG[value])) 351 #else: 352 #l.append((value, name)) 353 #por = self.getNextPeerAcc(por) 354 355 ## sort the list of status values and names by priority, highest first) 356 #l.sort() 357 358 #last = -1 359 #for value, name in l: 360 #if last != value: 361 #last = value 362 #self.sayState(text=STATUS_MSG[value], template='%s,') 363 #brailleout.append('%s: ' % (STATUS_MSG[value])) 364 #self.sayState(text=name, template='%s,') 365 #brailleout.append('%s, ' % (name)) 366 ## output to Braille device 367 #self.doTask('braille text', text=''.join(brailleout)) 368 369 ## 370 ## Tasks executed by events 371 ## 372 373 #class ActivatePidginWindow(Task.ViewTask): 374 #''' 375 #Task that handles a L{AEEvent.ViewChange}. 376 #''' 377 #def executeGained(self, por, title, **kwargs): 378 #''' 379 #Prevents the window title from being announced if it is the chat window, 380 #since better information is given for the chat window on the subsequent 381 #focus change event. Accomplished by stopping propagation of the event. 382 383 #@param por: Point of regard to the root of the new view 384 #@type por: L{AEPor} 385 #@param title: Title of the newly activated window 386 #@type title: string 387 #''' 388 #self.script.last_convo = AEPor() 389 #tab_list_por = self.script.getActivePageTabListPOR() 390 #print 'GAIM:', tab_list_por 391 ## test to see if not a chat window 392 #if tab_list_por is None: 393 #return True # allow other Scripts to handle the view change 394 ## must be a chat window 395 #else: 396 #if not self.script.initialized: 397 #self.script.setPidginVersion() 398 #self.script.initialized = True 399 ## don't allow the view change event to propagate 400 #return False 401 402 #class HandleFocusChange(Task.FocusTask): 403 #''' 404 #Task that handles a L{AEEvent.FocusChange}. 405 #''' 406 #GAIM2_HISTORY_PATH = (0,0,0,0,0,0,0) #history text panel 407 #GAIM2_COMPOSE_PATH = (0,0,1,0,0,0,0,2,0) # compose text panel - pidgin2 remote 408 #GAIM2_ALT_COMPOSE_PATH = (0,0,1,0,1,0,0,2,0) # compose text panel - pidgin1.5 409 410 #def executeGained(self, por, **kwargs): 411 ## get 'page tab list' 412 #tab_list_por = self.script.getActivePageTabListPOR() 413 #if tab_list_por is None: 414 ## let the event propagate 415 #return True 416 417 ## possibly stop prior speech 418 #self.mayStop() 419 ## and prevent this speech from being interrupted 420 #self.inhibitMayStop() 421 422 ## get selected conversation tab 423 #selected_tab_por = self.getFirstSelected(tab_list_por) 424 425 ## check if we should announce the state of the current convo or not 426 #if selected_tab_por != self.script.last_convo: 427 #name = self.getAccName(selected_tab_por) 428 #self.saySection(text=name, template=_('chat with %s')) 429 #value = self.script.getTypingStatus(selected_tab_por) 430 #self.sayState(text=STATUS_MSG[value]) 431 #self.script.last_convo = selected_tab_por 432 433 ## locate message history/compose text box PORs 434 ## pidgin 2 local client 435 #if self.script.is_pidgin2: 436 #self.script.chat_history_por = \ 437 #self.getAccFromPath(selected_tab_por, *self.GAIM2_HISTORY_PATH) 438 #self.script.chat_compose_por = \ 439 #self.getAccFromPath(selected_tab_por, *self.GAIM2_COMPOSE_PATH) 440 #if (self.script.chat_compose_por is None or 441 #not self.hasAccRole('text', self.script.chat_compose_por)): 442 #self.script.chat_compose_por = \ 443 #self.getAccFromPath(selected_tab_por, *self.GAIM2_ALT_COMPOSE_PATH) 444 #print 'alt', self.script.chat_compose_por 445 ## pidgin 1.5 local client 446 #else: 447 #self.script.chat_history_por = \ 448 #self.getAccFromPath(selected_tab_por, *HISTORY_PATH) 449 #self.script.chat_compose_por = \ 450 #self.getAccFromPath(selected_tab_por, *COMPOSE_PATH) 451 452 ## tell user which text area is focused 453 #self.script.is_history_focused = \ 454 #self.hasAccState('focused', self.script.chat_history_por) 455 #if self.script.is_history_focused: 456 ##if self.hasAccState('focused', self.script.chat_history_por): 457 #self.saySection(text=_('history,')) # this odd syntax supports i18n 458 #self.script.last_history_caret = AEPor() # reset 459 #return False 460 #elif self.hasAccState('focused', self.script.chat_compose_por): 461 ##elif self.hasAccState('focused', self.script.chat_compose_por): 462 #self.saySection(text=_('compose,')) # this odd syntax supports i18n 463 #return False 464 ##else: 465 ## return True # propagate handling of the event (default) 466 467 #class HandleSelectorChange(Task.SelectorTask): 468 #''' 469 #Task that tracks text selection changes. Used to updated the selection flag 470 #so the L{HandleCaretChange.executeDeleted} method can decide whether or not 471 #to allow reporting of deleted text. 472 #''' 473 #def executeText(self, por, text, **kwargs): 474 #''' 475 #Sets the selection flag to True if some text is selected else sets it to 476 #False. 477 478 #@param por: Point of regard to the text caret 479 #@type por: L{AEPor} 480 #@param text: Currently selected text 481 #@type text: string 482 #''' 483 #if text: 484 #self.script.selection = True 485 #else: 486 #self.script.selection = False 487 #return True 488 489 #class ReadIncoming(Task.CaretTask): 490 #''' 491 #Reads incoming messages. 492 #''' 493 #def executeInserted(self, por, text, text_offset, layer, **kwargs): 494 #''' 495 #Speaks text that starts with a new line character. This indicates a new 496 #line of text has been inserted into the message history. 497 498 #@param por: Point of regard where the caret event occurred 499 #@type por: L{AEPor} 500 #@param text: The text passed during the move 501 #@type text: string 502 #@param text_offset: The offset of the new caret position 503 #@type text_offset: integer 504 #@param layer: Layer of the event, focus, tier, or background 505 #@type layer: integer 506 #''' 507 ## convoluted logic is necessary in order to minimize expensive 508 ## compareAncestorRoles calls. 509 #if (not self.script_state.ReadBackground and 510 #not self.script_state.BrailleBackground and 511 #layer == AEConstants.LAYER_BACKGROUND): 512 ## don't output background messages if the user has it disabled. 513 #return 514 515 #rv = self.compareAncestorRoles(por, 'scroll pane', 'filler', 'panel', 516 #'filler', 'split pane', 'filler', 517 #'page tab') 518 519 #if rv and (layer != AEConstants.LAYER_BACKGROUND or 520 #(layer == AEConstants.LAYER_BACKGROUND and 521 #self.script_state.ReadBackground)): 522 ## queue up text to speak 523 #self.sayItem(text=text) 524 525 #if rv and (layer != AEConstants.LAYER_BACKGROUND or 526 #(layer == AEConstants.LAYER_BACKGROUND and 527 #self.script_state.BrailleBackground)): 528 ## output to braille device 529 #self.doTask('braille text', text=text) 530 531 532 #class HandleCaretChange(Task.CaretTask): 533 #''' 534 #Task that handles a L{AEEvent.CaretChange}. Used to read an entire message in 535 #chat history, rather than simply the current line. The L{executeMoved} method 536 #finds the beginning and end of the current message, truncates the timestamp 537 #and user name when redundant, then reads the message. 538 #''' 539 #def executeMoved(self, por, text, text_offset, **kwargs): 540 #''' 541 #Announces an entire message from a remote user by looking for hard line 542 #breaks (\\n) when the caret moves to a position just after or just before 543 #the break character. If the caret is anywhere else, lets other L{AEScript <AEScript.AEScript>}s do 544 #their default caret processing. 545 546 #@param por: Point of regard where the caret event occurred 547 #@type por: L{AEPor} 548 #@param text: The text passed during the move 549 #@type text: string 550 #@param text_offset: The offset of the new caret position 551 #@type text_offset: integer 552 #''' 553 ## debugging code for handleTableChange, since we may or may not get 554 ## multiple events when a remote buddy logs off, announce when caret changes 555 ## just as a test, not for final code. 556 ##if self.script.last_row_inserted_por is not None: 557 ## print "last_row_inserted_por" , self.script.last_row_inserted_por 558 ## self.script.last_row_inserted_por = None 559 ## could eliminate by setting is_history_focused = False when appropriate 560 #tab_list_por = self.script.getActivePageTabListPOR() 561 ## if chat window and chat history have focus 562 #if tab_list_por is not None and self.script.is_history_focused: 563 ## say line when item_offset changes 564 #if (not por.isSameItem(self.script.last_history_caret)): 565 ## get the start of the line (character after a \n) 566 #start = self.getStartOfHardLine(por) 567 ## get the end of the line (next encountered \n) 568 #end = self.getEndOfHardLine(por) 569 570 ## store the current POR 571 #self.script.last_history_caret = por 572 ## if we're not at the start or end of a true message line, let 573 ## other Scripts handle the caret event unless at start/end of msg 574 #if por != end and por != start: 575 #return True 576 577 ## get all the text between the start and end PORs 578 #msg = self.getAccTextBetween(start, end) 579 580 #self.mayStop() 581 #self.sayItem(text=msg) 582 ##self.inhibitMayStop() 583 #return False 584 585 ## respond to caret movement on same line 586 ## just let other Scripts handle this case 587 #else: 588 #self.script.last_history_caret = por 589 #return True 590 591 ## not in chat history 592 #else: 593 #return True 594 595 #def executeInserted(self, **kwargs): 596 #'''Resets the selection flag.''' 597 #self.script.selection = False 598 #return True 599 600 #def executeDeleted(self, text, **kwargs): 601 #''' 602 #Consumes the deletion event if the selection flag is False and more than 603 #one character of text was deleted (i.e. a message was sent). Avoids 604 #announcing the sent text as "Backspace <text>" as well as the text that 605 #appears in the message history. If the selection flag is True, resets it. 606 607 #@param text: The text deleted 608 #@type text: string 609 #''' 610 #if not self.script.selection and len(text) > 1: 611 #return False 612 #self.script.selection = False 613 #return True 614 615 #class HandlePropertyChange(Task.PropertyTask): 616 #''' 617 #Task that handles a L{AEEvent.PropertyChange}. 618 #''' 619 #def execute(self, por, name, value, **kwargs): 620 #''' 621 #If in a chat window, check to see if the text color properties of a 622 #conversation tab have changed. Announce change if to anything other than 623 #'idle' (ie. active typing, paused typing, away, away idle, logged out). 624 #''' 625 #is_chat_window = self.script.getActivePageTabListPOR() 626 ## test to see if a chat window and if a conversation page tab 627 #if is_chat_window is not None and self.hasAccRoleName('page tab', por): 628 #user = self.getAccName(por) 629 #status = self.script.getTypingStatus(por) 630 ##print "%s: %s: %s" %(name, STATUS_MSG[status], por) 631 ## don't report idle status, we already report paused and new message 632 #if status != IDLE_STATUS: 633 ##print "PidginScript::Property change:", por, name, value 634 ##print "%s: %s: %s" %(user, STATUS_MSG[status], por) 635 #self.sayState(text=(user, STATUS_MSG[status]), template='%s %s,') 636 #return True 637 638 639 #class BuddySignOnOff(Task.TableTask): 640 #''' 641 #Task that handles a L{AEEvent.TableChange}. 642 643 #These events will be used to know when a remote buddy logs in/out, however 644 #current information makes the "in/out" determination unreliable. Bugs are 645 #being filed against Pidgin. Therefore, this script does not currently register 646 #to handle TableChange events. 647 #''' 648 649 #def executeTableRowInserted(self, por, first_child_por, last_child_por, 650 #layer, **kwargs): 651 #''' 652 #Executes this task in response to a row-inserted table change event. 653 #Called by L{Task.TableTask.execute}. 654 655 #@param por: The L{AEPor} for the related accessible 656 #@type por: L{AEPor} 657 #@param first_child_por: The L{AEPor} of first inserted row 658 #@type first_child_por: L{AEPor} 659 #@param last_child_por: The L{AEPor} of last inserted row 660 #@type last_child_por: L{AEPor} 661 #@param layer: Layer on which the event occurred 662 #@type layer: integer 663 #''' 664 ##print "PidginScript::executeTableRowInserted()", por, first_child_por, \ 665 ## last_child_por, layer 666 #frame_name = self.getWindowTitle(por) 667 ## only handle table change events from buddy list (don't announce when 668 ## conversation tab order changes, assume only a sighted user would do that). 669 #if frame_name == "Buddy List": 670 ##print "1" , self.getItemText(first_child_por) 671 ##print "2" , self.getItemText(last_child_por) 672 ## may be used in case where, on sign-off, multiple inserts fire 673 ## self.script.last_row_inserted_por = first_child_por 674 ## name = self.getItemText(self.script.last_row_inserted_por) 675 ##print "%s logged in" %name 676 #status = STATUS_MSG[LOGIN_STATUS] 677 #self.sayState(text=(name, status), template='%s: %s,') 678 #return True 679 680 #def executeTableRowDeleted(self, por, first_child_por, last_child_por, 681 #layer, **kwargs): 682 #''' 683 #Executes this task in response to a row-deleted table change event. 684 #Called by L{execute}. 685 686 #@param por: The L{AEPor} for the related accessible 687 #@type por: L{AEPor} 688 #@param first_child_por: The L{AEPor} of first deleted row 689 #@type first_child_por: L{AEPor} 690 #@param last_child_por: The L{AEPor} of last deleted row 691 #@type last_child_por: L{AEPor} 692 #@param layer: Layer on which the event occurred 693 #@type layer: integer 694 #''' 695 ##print "PidginScript::executeTableRowDeleted()" , por, first_child_por, \ 696 ## last_child_por, layer 697 #frame_name = self.getWindowTitle(por) 698 #if frame_name == "Buddy List": 699 ##print "1" , self.getItemText(first_child_por) 700 ##print "2" , self.getItemText(last_child_por) 701 #name = self.getItemText(first_child_por) 702 ##print "%s logged out" %name 703 #status = (name, STATUS_MSG[LOGOUT_STATUS]) 704 #self.sayState(text=status, template='%s: %s,') 705 #return True 706