1 #Copyright (C) 2008 Codethink Ltd
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.
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.
17 from interfaces import *
18 from accessible import Accessible
19 from base import Enum, _repack_tuple
20 from factory import accessible_factory
26 "TEXT_BOUNDARY_WORD_START",
27 "TEXT_BOUNDARY_WORD_END",
28 "TEXT_BOUNDARY_SENTENCE_START",
29 "TEXT_BOUNDARY_SENTENCE_END",
30 "TEXT_BOUNDARY_LINE_START",
31 "TEXT_BOUNDARY_LINE_END",
39 #------------------------------------------------------------------------------
41 class TEXT_BOUNDARY_TYPE(Enum):
43 0:'TEXT_BOUNDARY_CHAR',
44 1:'TEXT_BOUNDARY_WORD_START',
45 2:'TEXT_BOUNDARY_WORD_END',
46 3:'TEXT_BOUNDARY_SENTENCE_START',
47 4:'TEXT_BOUNDARY_SENTENCE_END',
48 5:'TEXT_BOUNDARY_LINE_START',
49 6:'TEXT_BOUNDARY_LINE_END',
52 TEXT_BOUNDARY_CHAR = TEXT_BOUNDARY_TYPE(0)
53 TEXT_BOUNDARY_LINE_END = TEXT_BOUNDARY_TYPE(6)
54 TEXT_BOUNDARY_LINE_START = TEXT_BOUNDARY_TYPE(5)
55 TEXT_BOUNDARY_SENTENCE_END = TEXT_BOUNDARY_TYPE(4)
56 TEXT_BOUNDARY_SENTENCE_START = TEXT_BOUNDARY_TYPE(3)
57 TEXT_BOUNDARY_WORD_END = TEXT_BOUNDARY_TYPE(2)
58 TEXT_BOUNDARY_WORD_START = TEXT_BOUNDARY_TYPE(1)
60 #------------------------------------------------------------------------------
62 class TEXT_CLIP_TYPE(Enum):
70 TEXT_CLIP_BOTH = TEXT_CLIP_TYPE(3)
71 TEXT_CLIP_MAX = TEXT_CLIP_TYPE(2)
72 TEXT_CLIP_MIN = TEXT_CLIP_TYPE(1)
73 TEXT_CLIP_NONE = TEXT_CLIP_TYPE(0)
75 #------------------------------------------------------------------------------
77 class Text(Accessible):
79 The text interface should be implemented by objects which place
80 textual information onscreen as character strings or glyphs.
81 The text interface allows access to textual content, including
82 display attributes and semantic hints associated with runs of
83 text, and access to bounding box information for glyphs and substrings.
84 It also allows portions of textual content to be selected, if
85 the object's StateSet includes STATE_SELECTABLE_TEXT.
86 In some cases a Text object may have, as its content, an empty
87 string. In particular this can occur in the case of Hypertext
88 objects which do not display explicitly textual information onscreen,
89 as Hypertext is derived from the Text interface.
90 Typographic and semantic attributes of onscreen textual content,
91 for instance typeface, weight, language, and such qualities as
92 'emphasis' or 'blockquote', are represented as text attributes.
93 Contiguous sequences of characters over which these attributes
94 are unchanged are referred to as "attribute runs", and are available
95 via Text::getAttributeRun. Where possible, implementing clients
96 will report textual attributes which are the same over the entire
97 text object, for instance those inherited from a default or document-scope
98 style, via getDefaultAttributes instead of reporting them explicitly
99 for each character. Therefore, for any span of text, the attributes
100 in effect are the union of the set returned by Text::getDefaultAttributes,
101 and the set returned at a particular character offset via Text::getAttributeRun.
104 def addSelection(self, index):
106 The result of calling addSelection on objects which already have
107 one selection present, and which do not include STATE_MULTISELECTABLE,
108 is undefined, other than the return value.
109 @return True of the selection was successfully added, False otherwise.
110 Selection may fail if the object does not support selection of
111 text (see STATE_SELECTABLE_TEXT), if the object does not support
112 multiple selections and a selection is already defined, or for
113 other reasons (for instance if the user does not have permission
114 to copy the text into the relevant selection buffer).
116 func = self.get_dbus_method("addSelection", dbus_interface=ATSPI_TEXT)
119 def getAttributeRun(self, offset, startOffset, endOffset, includeDefaults):
121 Query a particular text object for the text attributes defined
122 at a given offset, obtaining the start and end of the "attribute
123 run" over which these attributes are currently invariant. Text
124 attributes are those presentational, typographic, or semantic
125 attributes or qualitites which apply to a range of text specifyable
126 by starting and ending offsets. Attributes relevant to localization
127 should be provided in accordance with the w3c "Internationalization
128 and Localization Markup Requirements", http://www.w3.org/TR/2005/WD-itsreq-20051122/
129 Other text attributes should choose their names and value semantics
130 in accordance with relevant standards such as CSS level 2 (http://www.w3.org/TR/1998/REC-CSS2-19980512),
131 XHTML 1.0 (http://www.w3.org/TR/2002/REC-xhtml1-20020801), and
132 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/). Those attributes
133 from the aforementioned specifications and recommendations which
134 do not concern typographic, presentational, or semantic aspects
135 of text should be exposed via the more general Accessible::getAttributes()
137 For example, CSS attributes which should be exposed on text (either
138 as default attributes, or as explicitly-set attributes when non-default
139 values are specified in the content view) include the Font attributes
140 (i.e. "css2:font-weight", "css2:font-style"), the "css2:color"
141 and "css2:background-color" attributes, and "css2:text-decoration"
143 If includeDefaults is TRUE, then this AttributeSet should include
144 the default attributes as well as those which are explicitly
145 assigned to the attribute run in question. startOffset and endOffset
146 will be back-filled to indicate the start and end of the attribute
147 run which contains 'offset' - an attribute run is a contiguous
148 section of text whose attributes are homogeneous.
150 the offset of the character whose attributes will be reported.
152 backfilled with the starting offset of the character range over
153 which all text attributes match those of offset, i.e. the start
154 of the homogeneous attribute run including offset.
156 backfilled with the offset of the first character past the character
157 range over which all text attributes match those of offset, i.e.
158 the character immediately after the homogeneous attribute run
160 @param : includeDefaults
161 if False, the call should only return those attributes which
162 are explicitly set on the current attribute run, omitting any
163 attributes which are inherited from the default values. See also
164 Text::getDefaultAttributes.
165 @return the AttributeSet defined at offset, optionally including
166 the 'default' attributes.
168 func = self.get_dbus_method("getAttributeRun", dbus_interface=ATSPI_TEXT)
169 attr = func(offset, startOffset, endOffset, includeDefaults)
170 return [key + ':' + value for key, value in attr.values()]
172 def getAttributeValue(self, offset, attributeName, startOffset, endOffset, defined):
174 Get the string value of a named attribute at a given offset,
177 the offset of the character for which the attribute run is to
179 @param : attributeName
180 the name of the attribute for which the value is to be returned,
183 back-filled with the offset of the first character in the attribute
184 run containing the character at offset.
186 back-filled with the offset of the first character past the end
187 of the attribute run containing the character at offset.
189 back-filled with True if the attributeName has a defined value
190 at offset, False otherwise.
191 @return the value of attribute (name-value pair) corresponding
192 to "name", if defined.
194 func = self.get_dbus_method("getAttributeValue", dbus_interface=ATSPI_TEXT)
195 return func(offset, attributeName, startOffset, endOffset, defined)
197 def getAttributes(self, offset):
199 getAttributes is deprecated in favor of getAttributeRun.
200 @return the attributes at offset, as a semicolon-delimited set
201 of colon-delimited name-value pairs.
203 func = self.get_dbus_method("getAttributes", dbus_interface=ATSPI_TEXT)
204 return [key + ':' + value for key, value in func(dbus.Int32(offset)).values()]
206 def getBoundedRanges(self, x, y, width, height, coordType, xClipType, yClipType):
207 #TODO Return a list of range structures
209 Return the text content within a bounding box, as a list of Range
210 structures. Depending on the TEXT_CLIP_TYPE parameters, glyphs
211 which are clipped by the bounding box (i.e. which lie partially
212 inside and partially outside it) may or may not be included in
215 the minimum x ( i.e. leftmost) coordinate of the bounding box.
217 the minimum y coordinate of the bounding box.
219 the horizontal size of the bounding box. The rightmost bound
220 of the bounding box is (x + width);
222 the vertical size of the bounding box. The maximum y value of
223 the bounding box is (y + height);
225 If 0, the above coordinates are interpreted as pixels relative
226 to corner of the screen; if 1, the coordinates are interpreted
227 as pixels relative to the corner of the containing toplevel window.
229 determines whether text which intersects the bounding box in
230 the x direction is included.
232 determines whether text which intersects the bounding box in
233 the y direction is included.
235 func = self.get_dbus_method("getBoundedRanges", dbus_interface=ATSPI_TEXT)
236 return func(x, y, width, height, coordType, xClipType, yClipType)
238 def getCharacterAtOffset(self, offset):
242 @return an unsigned long integer whose value corresponds to the
243 UCS-4 representation of the character at the specified text offset,
244 or 0 if offset is out of range.
246 func = self.get_dbus_method("getCharacterAtOffset", dbus_interface=ATSPI_TEXT)
249 def getCharacterExtents(self, offset, x, y, width, height, coordType):
251 Obtain a the bounding box, as x, y, width, and height, of the
252 character or glyph at a particular character offset in this object's
253 text content. The coordinate system in which the results are
254 reported is specified by coordType. If an onscreen glyph corresponds
255 to multiple character offsets, for instance if the glyph is a
256 ligature, the bounding box reported will include the entire glyph
257 and therefore may apply to more than one character offset.
259 the character offset of the character or glyph being queried.
261 the minimum horizontal coordinate of the bounding box of the
262 glyph representing the character at offset.
264 the minimum vertical coordinate of the bounding box of the glyph
265 representing the character at offset.
267 the horizontal extent of the bounding box of the glyph representing
268 the character at offset.
270 the vertical extent of the bounding box of the glyph representing
271 the character at offset.
273 If 0, the results will be reported in screen coordinates, i.e.
274 in pixels relative to the upper-left corner of the screen, with
275 the x axis pointing right and the y axis pointing down. If 1,
276 the results will be reported relative to the containing toplevel
277 window, with the x axis pointing right and the y axis pointing
280 func = self.get_dbus_method("getCharacterExtents", dbus_interface=ATSPI_TEXT)
281 return func(offset, x, y, width, height, coordType)
283 def getDefaultAttributeSet(self):
285 Return an AttributeSet containing the text attributes which apply
286 to all text in the object by virtue of the default settings of
287 the document, view, or user agent; e.g. those attributes which
288 are implied rather than explicitly applied to the text object.
289 For instance, an object whose entire text content has been explicitly
290 marked as 'bold' will report the 'bold' attribute via getAttributeRun(),
291 whereas an object whose text weight is inspecified may report
292 the default or implied text weight in the default AttributeSet.
294 func = self.get_dbus_method("getDefaultAttributeSet", dbus_interface=ATSPI_TEXT)
295 return [key + ':' + value for key, value in func().values()]
297 def getDefaultAttributes(self):
299 Deprecated in favor of getDefaultAttributeSet.
300 @return the attributes which apply to the entire text content,
301 but which were not explicitly specified by the content creator.
303 func = self.get_dbus_method("getDefaultAttributes", dbus_interface=ATSPI_TEXT)
304 return [key + ':' + value for key, value in func().values()]
306 def getNSelections(self):
308 Obtain the number of separate, contiguous selections in the current
309 Text object. Text objects which do not implement selection of
310 discontiguous text regions will always return '0' or '1'. Note
311 that "contiguous" is defined by continuity of the offsets, i.e.
312 a text 'selection' is defined by a start/end offset pair. In
313 the case of bidirectional text, this means that a continguous
314 selection may appear visually discontiguous, and vice-versa.
315 @return the number of contiguous selections in the current Text
318 func = self.get_dbus_method("getNSelections", dbus_interface=ATSPI_TEXT)
321 def getOffsetAtPoint(self, x, y, coordType):
323 Get the offset of the character at a given onscreen coordinate.
324 The coordinate system used to interpret x and y is determined
325 by parameter coordType.
329 if 0, the input coordinates are interpreted relative to the entire
330 screen, if 1, they are relative to the toplevel window containing
332 @return the text offset (as an offset into the character array)
333 of the glyph whose onscreen bounds contain the point x,y, or
334 -1 if the point is outside the bounds of any glyph.
336 func = self.get_dbus_method("getOffsetAtPoint", dbus_interface=ATSPI_TEXT)
337 return func(x, y, coordType)
339 def getRangeExtents(self, startOffset, endOffset, x, y, width, height, coordType):
341 Obtain the bounding box which entirely contains a given text
342 range. Negative values may be returned for the bounding box parameters
343 in the event that all or part of the text range is offscreen
344 or not mapped to the screen.
346 the offset of the first character in the specified range.
348 the offset of the character immediately after the last character
349 in the specified range.
351 an integer parameter which is back-filled with the minimum horizontal
352 coordinate of the resulting bounding box.
354 an integer parameter which is back-filled with the minimum vertical
355 coordinate of the resulting bounding box.
357 an integer parameter which is back-filled with the horizontal
358 extent of the bounding box.
360 an integer parameter which is back-filled with the vertical extent
363 If 0, the above coordinates are reported in pixels relative to
364 corner of the screen; if 1, the coordinates are reported relative
365 to the corner of the containing toplevel window.
367 func = self.get_dbus_method("getRangeExtents", dbus_interface=ATSPI_TEXT)
368 return func(startOffset, endOffset, x, y, width, height, coordType)
370 def getSelection(self, selectionNum, startOffset, endOffset):
372 The result of calling getSelection with an out-of-range selectionNum
373 (i.e. for a selection which does not exist) is not strictly defined,
374 but should set endOffset equal to startOffset.
375 @param : selectionNum
376 indicates which of a set of non-contiguous selections to modify.
378 back-filled with the starting offset of the resulting substring,
381 back-filled with the offset of the character immediately following
382 the resulting substring, if one exists.
384 func = self.get_dbus_method("getSelection", dbus_interface=ATSPI_TEXT)
385 return func(selectionNum, startOffset, endOffset)
387 def getText(self, startOffset, endOffset):
389 Obtain all or part of the onscreen textual content of a Text
390 object. If endOffset is specified as "-1", then this method will
391 return the entire onscreen textual contents of the Text object.
393 back-filled with the starting offset of the resulting substring,
396 back-filled with the offset of the character immediately following
397 the resulting substring, if one exists.
398 @return the textual content of the current Text object beginning
399 startOffset (inclusive) up to but not including the character
402 func = self.get_dbus_method("getText", dbus_interface=ATSPI_TEXT)
405 return func(dbus.Int32(startOffset), dbus.Int32(endOffset))
407 def getTextAfterOffset(self, offset, type, startOffset, endOffset):
409 Obtain a subset of the text content of an object which entirely
410 follows offset, delimited by character, word, line, or sentence
411 boundaries as specified by type. The starting and ending offsets
412 of the resulting substring are returned in startOffset and endOffset.
413 By definition, if such a substring exists, startOffset must be
416 the offset from which the substring search begins, and which
417 must lie before the returned substring.
419 the text-boundary delimiter which determines whether the returned
420 text constitures a character, word, line, or sentence (and possibly
421 attendant whitespace), and whether the start or ending of such
422 a substring forms the boundary condition.
424 back-filled with the starting offset of the resulting substring,
427 back-filled with the offset of the character immediately following
428 the resulting substring, if one exists.
429 @return a string which is a substring of the text content of
430 the object, delimited by the specified boundary condition.
432 func = self.get_dbus_method("getTextAfterOffset", dbus_interface=ATSPI_TEXT)
433 return func(offset, type, startOffset, endOffset)
435 def getTextAtOffset(self, offset, type):
437 Obtain a subset of the text content of an object which includes
438 the specified offset, delimited by character, word, line, or
439 sentence boundaries as specified by type. The starting and ending
440 offsets of the resulting substring are returned in startOffset
443 the offset from which the substring search begins, and which
444 must lie within the returned substring.
446 the text-boundary delimiter which determines whether the returned
447 text constitures a character, word, line, or sentence (and possibly
448 attendant whitespace), and whether the start or ending of such
449 a substring forms the boundary condition.
451 back-filled with the starting offset of the resulting substring,
454 back-filled with the offset of the character immediately following
455 the resulting substring, if one exists.
456 @return a string which is a substring of the text content of
457 the object, delimited by the specified boundary condition.
459 func = self.get_dbus_method("getTextAtOffset", dbus_interface=ATSPI_TEXT)
460 return _repack_tuple(func(offset, type))
462 def getTextBeforeOffset(self, offset, type, startOffset, endOffset):
464 Obtain a subset of the text content of an object which entirely
465 precedes offset, delimited by character, word, line, or sentence
466 boundaries as specified by type. The starting and ending offsets
467 of the resulting substring are returned in startOffset and endOffset.
468 By definition, if such a substring exists, endOffset is less
469 than or equal to offset.
471 the offset from which the substring search begins.
473 the text-boundary delimiter which determines whether the returned
474 text constitures a character, word, line, or sentence (and possibly
475 attendant whitespace), and whether the start or ending of such
476 a substring forms the boundary condition.
478 back-filled with the starting offset of the resulting substring,
481 back-filled with the offset of the character immediately following
482 the resulting substring, if one exists.
483 @return a string which is a substring of the text content of
484 the object, delimited by the specified boundary condition.
486 func = self.get_dbus_method("getTextBeforeOffset", dbus_interface=ATSPI_TEXT)
487 return func(offset, type, startOffset, endOffset)
489 def removeSelection(self, selectionNum):
491 Deselect the text contained in the specified selectionNum, if
492 such a selection exists, otherwise do nothing. Removal of a non-existant
493 selectionNum has no effect.
494 @param : selectionNum
495 indicates which of a set of non-contiguous selections to modify.
496 @return True if the selection was successfully removed, False
499 func = self.get_dbus_method("removeSelection", dbus_interface=ATSPI_TEXT)
500 return func(selectionNum)
502 def setCaretOffset(self, offset):
504 Programmatically move the text caret (visible or virtual, as
505 above) to a given position.
507 a long int indicating the desired character offset. Not all implementations
508 of Text will honor setCaretOffset requests, so the return value
509 below should be checked by the client.
510 @return TRUE if the request was carried out, or FALSE if the
511 caret could not be moved to the requested position.
513 func = self.get_dbus_method("setCaretOffset", dbus_interface=ATSPI_TEXT)
516 def setSelection(self, selectionNum, startOffset, endOffset):
518 Modify an existing selection's start or ending offset.
519 Calling setSelection for a selectionNum that is not already defined
520 has no effect. The result of calling setSelection with a selectionNum
521 greater than 0 for objects that do not include STATE_MULTISELECTABLE
523 @param : selectionNum
524 indicates which of a set of non-contiguous selections to modify.
526 the new starting offset for the selection
528 the new ending offset for the selection
529 @return True if the selection corresponding to selectionNum is
530 successfully modified, False otherwise.
532 func = self.get_dbus_method("setSelection", dbus_interface=ATSPI_TEXT)
533 return func(selectionNum, startOffset, endOffset)
535 def get_caretOffset(self):
536 return dbus.Int32(self._pgetter(self._dbus_interface, "caretOffset"))
539 The current offset of the text caret in the Text object. This
540 caret may be virtual, e.g. non-visual and notional-only, but
541 if an onscreen representation of the caret position is visible,
542 it will correspond to this offset. The caret offset is given
543 as a character offset, as opposed to a byte offset into a text
544 buffer or a column offset.
546 caretOffset = property(fget=get_caretOffset, doc=_caretOffsetDoc)
548 def get_characterCount(self):
549 return dbus.Int32(self._pgetter(self._dbus_interface, "characterCount"))
550 _characterCountDoc = \
552 The total current number of characters in the Text object, including
553 whitespace and non-spacing characters.
555 characterCount = property(fget=get_characterCount, doc=_characterCountDoc)
558 def __new__(cls, startOffset, endOffset, content, data):
559 list.__new__(cls, (startOffset, endOffset, content, data))
560 def __init__(self, startOffset, endOffset, content, data):
561 list.__init__(self, (startOffset, endOffset, content, data))
563 def _get_startOffset(self):
565 def _set_startOffset(self, val):
567 startOffset = property(fget=_get_startOffset, fset=_set_startOffset)
568 def _get_endOffset(self):
570 def _set_endOffset(self, val):
572 endOffset = property(fget=_get_endOffset, fset=_set_endOffset)
573 def _get_content(self):
575 def _set_content(self, val):
577 content = property(fget=_get_content, fset=_set_content)
580 def _set_data(self, val):
582 data = property(fget=_get_data, fset=_set_data)
584 # Register the accessible class with the factory.
585 accessible_factory.register_accessible_class(ATSPI_TEXT, Text)
587 #END----------------------------------------------------------------------------