2008-08-27 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / pyatspi / event.py
1 #Copyright (C) 2008 Codethink Ltd
2
3 #This library is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU Lesser General Public
5 #License version 2 as published by the Free Software Foundation.
6
7 #This program is distributed in the hope that it will be useful,
8 #but WITHOUT ANY WARRANTY; without even the implied warranty of
9 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 #GNU General Public License for more details.
11 #You should have received a copy of the GNU Lesser General Public License
12 #along with this program; if not, write to the Free Software
13 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14
15 import interfaces
16 from factory import create_accessible, add_accessible_class
17 from accessible import BoundingBox
18
19 __all__ = [
20                 "Event",
21                 "EventType",
22           ]
23
24 #------------------------------------------------------------------------------
25
26 class EventType(str):
27         """
28         Wraps the AT-SPI event type string so its components can be accessed 
29         individually as klass (can't use the keyword class), major, minor, and detail 
30         (klass_major_minor_detail).
31         
32         @note: All attributes of an instance of this class should be considered 
33                 public readable as it is acting a a struct.
34         @ivar klass: Most general event type identifier (object, window, mouse, etc.)
35         @type klass: string
36         @ivar major: Second level event type description
37         @type major: string
38         @ivar minor: Third level event type description
39         @type minor: string
40         @ivar detail: Lowest level event type description
41         @type detail: string
42         @ivar name: Full, unparsed event name as received from AT-SPI
43         @type name: string
44         @cvar format: Names of the event string components
45         @type format: 4-tuple of string
46         """
47         format = ('klass', 'major', 'minor', 'detail')
48
49         def __init__(self, name):
50                 """             
51                 Parses the full AT-SPI event name into its components
52                 (klass:major:minor:detail). If the provided event name is an integer
53                 instead of a string, then the event is really a device event.
54                 
55                 @param name: Full AT-SPI event name
56                 @type name: string
57                 @raise AttributeError: When the given event name is not a valid string 
58                 """
59                 # get rid of any leading and trailing '_' separators
60                 self.value = name.strip('_')
61                 self.name = self.value # Backward compatability
62                 self.klass = None
63                 self.major = None
64                 self.minor = None
65                 self.detail = None
66                 
67                 # split type according to delimiters
68                 split = self.value.split('_', 3)
69                 # loop over all the components
70                 for i in xrange(len(split)):
71                         # store values of attributes in this object
72                         setattr(self, self.format[i], split[i])
73
74 #------------------------------------------------------------------------------
75
76 class Event(object):
77         """
78         Wraps an AT-SPI event with a more Pythonic interface managing exceptions,
79         the differences in any_data across versions, and the reference counting of
80         accessibles provided with the event.
81         
82         @note: All unmarked attributes of this class should be considered public
83                 readable and writable as the class is acting as a record object.
84                 
85         @ivar type: The type of the AT-SPI event
86         @type type: L{EventType}
87         @ivar detail1: First AT-SPI event parameter
88         @type detail1: integer
89         @ivar detail2: Second AT-SPI event parameter
90         @type detail2: integer
91         @ivar any_data: Extra AT-SPI data payload
92         @type any_data: object
93         @ivar host_application: Application owning the event source
94         @type host_application: Accessibility.Application
95         @ivar source_name: Name of the event source at the time of event dispatch
96         @type source_name: string
97         @ivar source_role: Role of the event source at the time of event dispatch
98         @type source_role: Accessibility.Role
99         @ivar source: Source of the event
100         @type source: Accessibility.Accessible
101         """
102         def __init__(self, cache, source_path, source_application, name, event):
103                 """
104                 Extracts information from the provided event. If the event is a "normal" 
105                 event, pulls the detail1, detail2, any_data, and source values out of the
106                 given object and stores it in this object. If the event is a device event,
107                 key ID is stored in detail1, scan code is stored in detail2, key name, 
108                 key modifiers (e.g. ALT, CTRL, etc.), is text flag, and timestamp are 
109                 stored as a 4-tuple in any_data, and source is None (since key events are
110                 global).
111
112                 @param event: Event from an AT-SPI callback
113                 @type event: Accessibility.Event or Accessibility.DeviceEvent
114                 """
115                 self._cache = cache
116                 self._source_path = source_path
117                 self._source_application = source_application
118                 self._source = None
119                 self._application = None
120
121                 self._detail = event[0]
122                 self.type = EventType(name + '_' + self._detail)
123                 self.detail1 = event[1]
124                 self.detail2 = event[2]
125
126                 data = event[3]
127                 if name == "object_bounds_changed":
128                         self.any_data = BoundingBox(*data)
129                 else:
130                         self.any_data = data
131
132         @property
133         def host_application(self):
134                 if not self._application:
135                         application_root = self._cache[self._source_application]._get_root()
136                         return create_accessible(self._cache,
137                                                  self._source_application,
138                                                  application_root,
139                                                  interfaces.ATSPI_APPLICATION,
140                                                  connection=self._cache._connection)
141                 return self._application
142
143         @property
144         def source(self):
145                 if not self._source:
146                         self._source = create_accessible(self._cache,
147                                                          self._source_application,
148                                                          self._source_path,
149                                                          interfaces.ATSPI_ACCESSIBLE,
150                                                          connection=self._cache._connection)
151                 return self._source
152
153         @property
154         def source_name(self):
155                 return source.name
156
157         @property
158         def source_role(self):
159                 return source.getRole()
160
161         def __str__(self):
162                 """
163                 Builds a human readable representation of the event including event type,
164                 parameters, and source info.
165
166                 @return: Event description
167                 @rtype: string
168                 """
169                 return '%s(%s, %s, %s)\n\tsource: %s\n\thost_application: %s' % \
170                                          (self.type, self.detail1, self.detail2, self.any_data,
171                                                 self.source, self.host_application)
172
173 #END----------------------------------------------------------------------------