Skip to content

Commit

Permalink
Revert "Introducing table sayall commands (#13670)" (#13954)
Browse files Browse the repository at this point in the history
Reverts: #13670, #13901
Fixes #13927
Re-introduces: #13469

Summary of the issue:
The fix for #13927 is complex, and will need weeks of testing on alpha.
This means that #13469 is blocked until #13670 can be implemented with #13927 fixed.

Description of user facing changes
Removes table say all commands from 2022.3

Description of development approach
Revert PRs in the right order, fix up the release blurb

Testing strategy:
#13670 has been confirmed as the commit which broke #13927 using a git bisect.
The build from this code has been tested with bookworm.
  • Loading branch information
seanbudd committed Jul 27, 2022
1 parent 6eda79a commit 9d25bac
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 557 deletions.
302 changes: 92 additions & 210 deletions source/documentBase.py

Large diffs are not rendered by default.

159 changes: 40 additions & 119 deletions source/speech/sayAll.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
# Copyright (C) 2006-2021 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Babbage B.V., Bill Dengler,
# Julien Cochuyt

from abc import ABCMeta, abstractmethod
from enum import IntEnum
from typing import Callable, TYPE_CHECKING, Optional
from typing import Callable, TYPE_CHECKING
import weakref
import garbageHandler
from logHandler import log
Expand Down Expand Up @@ -37,7 +36,6 @@
class CURSOR(IntEnum):
CARET = 0
REVIEW = 1
TABLE = 2


SayAllHandler = None
Expand Down Expand Up @@ -97,23 +95,10 @@ def readObjects(self, obj: 'NVDAObjects.NVDAObject'):
self._getActiveSayAll = weakref.ref(reader)
reader.next()

def readText(
self,
cursor: CURSOR,
startPos: Optional[textInfos.TextInfo] = None,
nextLineFunc: Optional[Callable[[textInfos.TextInfo], textInfos.TextInfo]] = None,
shouldUpdateCaret: bool = True,
) -> None:
def readText(self, cursor: CURSOR):
self.lastSayAllMode = cursor
try:
if cursor == CURSOR.CARET:
reader = _CaretTextReader(self)
elif cursor == CURSOR.REVIEW:
reader = _ReviewTextReader(self)
elif cursor == CURSOR.TABLE:
reader = _TableTextReader(self, startPos, nextLineFunc, shouldUpdateCaret)
else:
raise RuntimeError(f"Unknown cursor {cursor}")
reader = _TextReader(self, cursor)
except NotImplementedError:
log.debugWarning("Unable to make reader", exc_info=True)
return
Expand Down Expand Up @@ -160,7 +145,7 @@ def stop(self):
self.walker = None


class _TextReader(garbageHandler.TrackedObject, metaclass=ABCMeta):
class _TextReader(garbageHandler.TrackedObject):
"""Manages continuous reading of text.
This is intended for internal use only.
Expand All @@ -182,41 +167,35 @@ class _TextReader(garbageHandler.TrackedObject, metaclass=ABCMeta):
"""
MAX_BUFFERED_LINES = 10

def __init__(self, handler: _SayAllHandler):
def __init__(self, handler: _SayAllHandler, cursor: CURSOR):
self.handler = handler
self.cursor = cursor
self.trigger = SayAllProfileTrigger()
self.reader = self.getInitialTextInfo()
self.reader = None
# Start at the cursor.
if cursor == CURSOR.CARET:
try:
self.reader = api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET)
except (NotImplementedError, RuntimeError) as e:
raise NotImplementedError("Unable to make TextInfo: " + str(e))
else:
self.reader = api.getReviewPosition()
# #10899: SayAll profile can't be activated earlier because they may not be anything to read
self.trigger.enter()
self.speakTextInfoState = SayAllHandler._makeSpeakTextInfoState(self.reader.obj)
self.numBufferedLines = 0
self.initialIteration = True

@abstractmethod
def getInitialTextInfo(self) -> textInfos.TextInfo:
...

@abstractmethod
def updateCaret(self, updater: textInfos.TextInfo) -> None:
...

def shouldReadInitialPosition(self) -> bool:
return False

def nextLineImpl(self) -> bool:
"""
Advances cursor to the next reading chunk (e.g. paragraph).
@return: C{True} if advanced successfully, C{False} otherwise.
"""
# Collapse to the end of this line, ready to read the next.
try:
self.reader.collapse(end=True)
except RuntimeError:
# This occurs in Microsoft Word when the range covers the end of the document.
# without this exception to indicate that further collapsing is not possible,
# say all could enter an infinite loop.

return False
def nextLine(self):
if not self.reader:
log.debug("no self.reader")
# We were stopped.
return
if not self.reader.obj:
log.debug("no self.reader.obj")
# The object died, so we should too.
self.finish()
return
bookmark = self.reader.bookmark
# Expand to the current line.
# We use move end rather than expand
# because the user might start in the middle of a line
Expand All @@ -232,25 +211,8 @@ def nextLineImpl(self) -> bool:
self.handler.speechWithoutPausesInstance.speakWithoutPauses([cb, EndUtteranceCommand()])
else:
self.finish()
return False
return True

def nextLine(self):
if not self.reader:
log.debug("no self.reader")
# We were stopped.
return
if not self.reader.obj:
log.debug("no self.reader.obj")
# The object died, so we should too.
self.finish()
return
if not self.initialIteration or not self.shouldReadInitialPosition():
if not self.nextLineImpl():
self.finish()
return
self.initialIteration = False
bookmark = self.reader.bookmark

# Copy the speakTextInfoState so that speak callbackCommand
# and its associated callback are using a copy isolated to this specific line.
state = self.speakTextInfoState.copy()
Expand Down Expand Up @@ -282,6 +244,15 @@ def _onLineReached(obj=self.reader.obj, state=state):
# Update the textInfo state ready for when speaking the next line.
self.speakTextInfoState = state.copy()

# Collapse to the end of this line, ready to read the next.
try:
self.reader.collapse(end=True)
except RuntimeError:
# This occurs in Microsoft Word when the range covers the end of the document.
# without this exception to indicate that further collapsing is not possible,
# say all could enter an infinite loop.
self.finish()
return
if not spoke:
# This line didn't include a natural pause, so nothing was spoken.
self.numBufferedLines += 1
Expand All @@ -300,7 +271,10 @@ def lineReached(self, obj, bookmark, state):
# We've just started speaking this line, so move the cursor there.
state.updateObj()
updater = obj.makeTextInfo(bookmark)
self.updateCaret(updater)
if self.cursor == CURSOR.CARET:
updater.updateCaret()
if self.cursor != CURSOR.CARET or config.conf["reviewCursor"]["followCaret"]:
api.setReviewPosition(updater, isCaret=self.cursor == CURSOR.CARET)
winKernel.SetThreadExecutionState(winKernel.ES_SYSTEM_REQUIRED)
if self.numBufferedLines == 0:
# This was the last line spoken, so move on.
Expand Down Expand Up @@ -342,59 +316,6 @@ def stop(self):
def __del__(self):
self.stop()


class _CaretTextReader(_TextReader):
def getInitialTextInfo(self) -> textInfos.TextInfo:
try:
return api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET)
except (NotImplementedError, RuntimeError) as e:
raise NotImplementedError("Unable to make TextInfo: ", e)

def updateCaret(self, updater: textInfos.TextInfo) -> None:
updater.updateCaret()
if config.conf["reviewCursor"]["followCaret"]:
api.setReviewPosition(updater, isCaret=True)


class _ReviewTextReader(_TextReader):
def getInitialTextInfo(self) -> textInfos.TextInfo:
return api.getReviewPosition()

def updateCaret(self, updater: textInfos.TextInfo) -> None:
api.setReviewPosition(updater, isCaret=False)


class _TableTextReader(_CaretTextReader):
def __init__(
self,
handler: _SayAllHandler,
startPos: Optional[textInfos.TextInfo] = None,
nextLineFunc: Optional[Callable[[textInfos.TextInfo], textInfos.TextInfo]] = None,
shouldUpdateCaret: bool = True,
):
self.startPos = startPos
self.nextLineFunc = nextLineFunc
self.shouldUpdateCaret = shouldUpdateCaret
super().__init__(handler)

def getInitialTextInfo(self) -> textInfos.TextInfo:
return self.startPos or super().getInitialTextInfo()

def nextLineImpl(self) -> bool:
try:
self.reader = self.nextLineFunc(self.reader)
return True
except StopIteration:
return False

def shouldReadInitialPosition(self) -> bool:
return True

def updateCaret(self, updater: textInfos.TextInfo) -> None:
if self.shouldUpdateCaret:
return super().updateCaret(updater)


class SayAllProfileTrigger(config.ProfileTrigger):
"""A configuration profile trigger for when say all is in progress.
"""
Expand Down
19 changes: 9 additions & 10 deletions source/virtualBuffers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
import treeInterceptorHandler
import watchdog
from abc import abstractmethod
import documentBase


VBufStorage_findDirection_forward=0
VBufStorage_findDirection_back=1
Expand Down Expand Up @@ -642,14 +640,15 @@ def _iterTableCells(self, tableID, startPos=None, direction="next", row=None, co

def _getNearestTableCell(
self,
startPos: textInfos.TextInfo,
cell: documentBase._TableCell,
movement: documentBase._Movement,
axis: documentBase._Axis,
) -> textInfos.TextInfo:
tableID, origRow, origCol, origRowSpan, origColSpan = (
cell.tableID, cell.row, cell.col, cell.rowSpan, cell.colSpan
)
tableID,
startPos,
origRow,
origCol,
origRowSpan,
origColSpan,
movement,
axis
):
# Determine destination row and column.
destRow = origRow
destCol = origCol
Expand Down
26 changes: 19 additions & 7 deletions source/virtualBuffers/gecko_ia2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import aria
import config
from NVDAObjects.IAccessible import normalizeIA2TextFormatField, IA2TextTextInfo
import documentBase


def _getNormalizedCurrentAttrs(attrs: textInfos.ControlField) -> typing.Dict[str, typing.Any]:
Expand Down Expand Up @@ -549,13 +548,26 @@ def _getTableCellAt(self,tableID,startPos,destRow,destCol):

def _getNearestTableCell(
self,
startPos: textInfos.TextInfo,
cell: documentBase._TableCell,
movement: documentBase._Movement,
axis: documentBase._Axis,
) -> textInfos.TextInfo:
tableID,
startPos,
origRow,
origCol,
origRowSpan,
origColSpan,
movement,
axis,
):
# Skip the VirtualBuffer implementation as the base BrowseMode implementation is good enough for us here.
return super(VirtualBuffer, self)._getNearestTableCell(startPos, cell, movement, axis)
return super(VirtualBuffer, self)._getNearestTableCell(
tableID,
startPos,
origRow,
origCol,
origRowSpan,
origColSpan,
movement,
axis
)

def _get_documentConstantIdentifier(self):
try:
Expand Down

0 comments on commit 9d25bac

Please sign in to comment.