Coverage Report - orca.find

ModuleCoverage %
orca.find
13%
1
# Orca
2
#
3
# Copyright 2006 Sun Microsystems Inc.
4
#
5
# This library is free software; you can redistribute it and/or
6
# modify it under the terms of the GNU Library General Public
7
# License as published by the Free Software Foundation; either
8
# version 2 of the License, or (at your option) any later version.
9
#
10
# This library is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
# Library General Public License for more details.
14
#
15
# You should have received a copy of the GNU Library General Public
16
# License along with this library; if not, write to the
17
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
# Boston, MA 02111-1307, USA.
19
20 1
"""Provides support for a flat review find."""
21
22 1
__id__        = "$Id: find.py 1774 2006-12-02 23:45:12Z richb $"
23 1
__version__   = "$Revision: 1774 $"
24 1
__date__      = "$Date: 2006-12-02 15:45:12 -0800 (Sat, 02 Dec 2006) $"
25 1
__copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc."
26 1
__license__   = "LGPL"
27
28
29 1
import copy
30 1
import re
31
32 1
import braille
33 1
import debug
34 1
import flat_review
35 1
import orca_state
36 1
import speech
37
38 1
from orca_i18n import _    # for gettext support
39
40 2
class SearchQuery:
41
    """Represents a search that the user wants to perform."""
42
43 1
    def __init__(self):
44
        """Creates a new SearchQuery. A searchQuery has the following
45
           properties:
46
47
           searchString     - the string to find
48
           searchBackwards  - if true, search upward for matches
49
           caseSensitive    - if true, case counts
50
           matchEntireWord  - if true, only match on the entire string
51
           startAtTop       - if true, begin the search from the top of
52
                              the window, rather than at the current
53
                              location
54
           windowWrap       - if true, when the top/bottom edge of the
55
                              window is reached wrap to the bottom/top
56
                              and continue searching
57
        """
58
59 0
        self.searchString = ""
60 0
        self.searchBackwards = False
61 0
        self.caseSensitive = False
62 0
        self.matchEntireWord = False
63 0
        self.windowWrap = False
64 0
        self.startAtTop = False
65
66 0
        self.debugLevel = debug.LEVEL_FINEST
67
68 1
    def debugContext(self, context, string):
69 0
        debug.println(self.debugLevel, \
70 0
            "------------------------------------------------------------")
71 0
        debug.println(self.debugLevel, \
72 0
                      "findQuery: %s line=%d zone=%d word=%d char=%d" \
73
                      % (string, context.lineIndex, context.zoneIndex, \
74
                                 context.wordIndex, context.charIndex))
75
76 0
        debug.println(self.debugLevel, \
77 0
                      "Number of lines: %d" % len(context.lines))
78 0
        debug.println(self.debugLevel, \
79 0
                      "Number of zones in current line: %d" % \
80
                      len(context.lines[context.lineIndex].zones))
81 0
        debug.println(self.debugLevel, \
82 0
                      "Number of words in current zone: %d" % \
83
           len(context.lines[context.lineIndex].zones[context.zoneIndex].words))
84
85 0
        debug.println(self.debugLevel, \
86 0
            "==========================================================\n\n")
87
88 1
    def dumpContext(self, context):
89 0
        print "DUMP"
90 0
        for i in range(0, len(context.lines)):
91 0
            print "  Line %d" % i
92 0
            for j in range(0, len(context.lines[i].zones)):
93 0
                print "    Zone: %d" % j
94 0
                for k in range(0, len(context.lines[i].zones[j].words)):
95 0
                    print "      Word %d = `%s` len(word): %d" % \
96
                        (k, context.lines[i].zones[j].words[k].string, \
97
                         len(context.lines[i].zones[j].words[k].string))
98
99 1
    def findQuery(self, context, justEnteredFlatReview):
100
        """Performs a search on the string specified in searchQuery.
101
102
           Arguments:
103
           - context: The context from active script
104
           - justEnteredFlatReview: If true, we began the search in focus
105
             tracking mode.
106
107
           Returns:
108
           - The context of the match, if found
109
        """
110
111
        # Get the starting context so that we can restore it at the end.
112
        #
113 0
        originalLineIndex = context.lineIndex
114 0
        originalZoneIndex = context.zoneIndex
115 0
        originalWordIndex = context.wordIndex
116 0
        originalCharIndex = context.charIndex
117
118 0
        debug.println(self.debugLevel, \
119 0
            "findQuery: original context line=%d zone=%d word=%d char=%d" \
120
                % (originalLineIndex, originalZoneIndex, \
121
                   originalWordIndex, originalCharIndex))
122
        # self.dumpContext(context)
123
124 0
        flags = re.LOCALE
125 0
        if not self.caseSensitive:
126 0
            flags = flags | re.IGNORECASE
127 0
        if self.matchEntireWord:
128 0
            regexp = "\\b" + self.searchString + "\\b"
129
        else:
130 0
            regexp = self.searchString
131 0
        pattern = re.compile(regexp,flags)
132
133 0
        debug.println(self.debugLevel, \
134 0
            "findQuery: startAtTop: %d  regexp: `%s`" \
135
                % (self.startAtTop, regexp))
136
137 0
        if self.startAtTop:
138 0
            context.goBegin(flat_review.Context.WINDOW)
139 0
            self.debugContext(context, "go begin")
140
141 0
        location = None
142 0
        found = False
143 0
        wrappedYet = False
144
145 0
        doneWithLine = False
146 0
        while not found:
147
            # Check the current line for the string.
148
            #
149 0
            [currentLine, x, y, width, height] = \
150
                 context.getCurrent(flat_review.Context.LINE)
151 0
            debug.println(self.debugLevel, \
152 0
                "findQuery: current line=`%s` x=%d y=%d width=%d height=%d" \
153
                    % (currentLine, x, y, width, height))
154
155 0
            if re.search(pattern, currentLine) and not doneWithLine:
156
                # It's on this line. Check the current zone for the string.
157
                #
158 0
                while not found:
159 0
                    [currentZone, x, y, width, height] = \
160
                         context.getCurrent(flat_review.Context.ZONE)
161 0
                    debug.println(self.debugLevel, \
162 0
                        "findQuery: current zone=`%s` x=%d y=%d width=%d height=%d" \
163
                            % (currentZone, x, y, width, height))
164
165 0
                    if re.search(pattern, currentZone):
166
                        # It's in this zone at least once.
167
                        #
168 0
                        theZone = context.lines[context.lineIndex] \
169
                                         .zones[context.zoneIndex]
170 0
                        startedInThisZone = \
171
                              (originalLineIndex == context.lineIndex) and \
172
                              (originalZoneIndex == context.zoneIndex)
173
174 0
                        if theZone.accessible.text and \
175
                           theZone.accessible.text.characterCount:
176
                            # Make a list of the character offsets for the
177
                            # matches in this zone.
178
                            #
179 0
                            allMatches = re.finditer(pattern, currentZone)
180 0
                            offsets = []
181 0
                            for m in allMatches:
182 0
                                offsets.append(m.start(0))
183 0
                            if self.searchBackwards:
184 0
                                offsets.reverse()
185
186 0
                            i = 0
187 0
                            while not found and (i < len(offsets)):
188 0
                                [nextInstance, offset] = \
189
                                   theZone.getWordAtOffset(offsets[i])
190 0
                                offsetDiff=nextInstance.index-context.wordIndex
191 0
                                if self.searchBackwards and \
192
                                              (offsetDiff < 0) or \
193
                                   not self.searchBackwards and \
194
                                              (offsetDiff > 0):
195 0
                                    context.wordIndex = nextInstance.index
196 0
                                    context.charIndex = 0
197 0
                                    found = True
198 0
                                elif not offsetDiff and \
199
                                    (not startedInThisZone or justEnteredFlatReview):
200
                                    # We landed on a match by happenstance.
201
                                    # This can occur when the nextInstance is
202
                                    # the first thing we come across.
203
                                    #
204 0
                                    found = True
205
                                else:
206 0
                                    i += 1
207 0
                    if not found:
208
                        # Locate the next zone to try again.
209
                        #
210 0
                        if self.searchBackwards:
211 0
                            moved = context.goPrevious( \
212
                                        flat_review.Context.ZONE, \
213 0
                                        flat_review.Context.WRAP_LINE)
214 0
                            self.debugContext(context, "[1] go previous")
215 0
                            context.goEnd(flat_review.Context.ZONE)
216 0
                            self.debugContext(context, "[1] go end")
217
                        else:
218 0
                            moved = context.goNext( \
219
                                        flat_review.Context.ZONE, \
220 0
                                        flat_review.Context.WRAP_LINE)
221 0
                            self.debugContext(context, "[1] go next")
222 0
                        if not moved:
223 0
                            doneWithLine = True
224 0
                            break
225
            else:
226
                # Locate the next line to try again.
227
                #
228 0
                if self.searchBackwards:
229 0
                    moved = context.goPrevious(flat_review.Context.LINE, \
230 0
                                               flat_review.Context.WRAP_LINE)
231 0
                    self.debugContext(context, "[2] go previous")
232
                else:
233 0
                    moved = context.goNext(flat_review.Context.LINE, \
234 0
                                           flat_review.Context.WRAP_LINE)
235 0
                    self.debugContext(context, "[2] go next")
236 0
                if moved:
237 0
                    if self.searchBackwards:
238 0
                        moved = context.goEnd(flat_review.Context.LINE)
239 0
                        self.debugContext(context, "[2] go end")
240
                else:
241
                    # Then we're at the screen's edge.
242
                    #
243 0
                    if self.windowWrap and not wrappedYet:
244 0
                        doneWithLine = False
245 0
                        wrappedYet = True
246 0
                        if self.searchBackwards:
247 0
                            speech.speak(_("Wrapping to Bottom"))
248 0
                            moved = context.goPrevious( \
249
                                    flat_review.Context.LINE, \
250 0
                                    flat_review.Context.WRAP_ALL)
251 0
                            self.debugContext(context, "[3] go previous")
252
                        else:
253 0
                            speech.speak(_("Wrapping to Top"))
254 0
                            moved = context.goNext( \
255
                                    flat_review.Context.LINE, \
256 0
                                    flat_review.Context.WRAP_ALL)
257 0
                            self.debugContext(context, "[3] go next")
258 0
                        if not moved:
259 0
                            debug.println(self.debugLevel, \
260 0
                                          "findQuery: cannot wrap")
261 0
                            break
262
                    else:
263 0
                        break
264 0
        if found:
265 0
            location = copy.copy(context)
266
267 0
        self.debugContext(context, "before setting original")
268 0
        context.setCurrent(originalLineIndex, originalZoneIndex, \
269 0
                           originalWordIndex, originalCharIndex)
270 0
        self.debugContext(context, "after setting original")
271
272 0
        if location:
273 0
            debug.println(self.debugLevel, \
274 0
                "findQuery: returning line=%d zone=%d word=%d char=%d" \
275
                    % (location.lineIndex, location.zoneIndex, \
276
                       location.wordIndex, location.charIndex))
277
278 0
        return location
279
280 1
def getLastQuery():
281
    """Grabs the last search query performed from orca_state.
282
283
       Returns:
284
       - A copy of the last search query, if it exists
285
    """
286
287 0
    lastQuery = copy.copy(orca_state.searchQuery)
288 0
    return lastQuery