diff --git a/source/appModules/poedit.py b/source/appModules/poedit.py index 8c916955bb9..2ca34423bfb 100644 --- a/source/appModules/poedit.py +++ b/source/appModules/poedit.py @@ -1,13 +1,12 @@ # A part of NonVisual Desktop Access (NVDA) # This file is covered by the GNU General Public License. # See the file COPYING for more details. -# Copyright (C) 2012-2023 Mesar Hameed, NV Access Limited, Leonard de Ruijter, Rui Fontes, Cyrille Bougot +# Copyright (C) 2012-2024 Mesar Hameed, NV Access Limited, Leonard de Ruijter, Rui Fontes, Cyrille Bougot """App module for Poedit 3.4+.""" from enum import IntEnum -import ctypes import api import appModuleHandler import controlTypes @@ -19,7 +18,6 @@ from NVDAObjects import NVDAObject from NVDAObjects.window import Window from scriptHandler import getLastScriptRepeatCount, script -from logHandler import log LEFT_TO_RIGHT_EMBEDDING = "\u202a" @@ -29,31 +27,35 @@ SCRCAT_POEDIT = _("Poedit") -class _WindowControlIdOffsetFromDataView(IntEnum): - """Window control ID's are not static, however, the order of ids stays the same. - Therefore, using a wxDataView control in the translations list as a reference, - we can safely calculate control ids accross releases or instances. - This class contains window control id offsets relative to the wxDataView window. - """ +class _WindowControlId(IntEnum): + """Static window control ID's as defined in poedit src/static_ids.h.""" - PRO_IDENTIFIER = -10 # This is a button in the free version - MAIN_SPLITTER_IDENTIFIER = -2 # The splitter that holds the translation list - TRANSLATION_WARNING = 17 - NEEDS_WORK_SWITCH = 21 + NEEDS_WORK_SWITCH = 10101 + """The "Needs work" toggle in editing area at the bottom""" + TRANSLATION_ISSUE_TEXT = 10102 + """ + The error or warning line above translation field + (hidden when there's no issue; ID is of the static text child window with issue's text) + """ -class _WindowControlIdOffsetFromSidebar(IntEnum): - """Window control ID's are not static, however, the order of ids stays the same. - Therefore, using the Sidebar window as a reference, - we can safely calculate control ids accross releases or instances. - This class contains window control id offsets relative to the Sidebar window. - Note that this Sidebar window itself is found relative to the dataview's ancestor splitter control. + PREVIOUS_SOURCE_TEXT = 10103 + """ + Text of previous source text + (msgid) for current item (shown in sidebar, may be hidden, is static control with the text) """ - PRO_OFFSET = -5 - OLD_SOURCE_TEXT = 36 - TRANSLATOR_NOTES = 39 - COMMENT = 42 + NOTES_FOR_TRANSLATOR = 10104 + """ + Text of notes for translators (extracted from source code) for current item + (shown in sidebar, may be hidden, is static control with the text) + """ + + TRANSLATOR_COMMENT = 10105 + """ + Text of translator's comment for current item + (shown in sidebar, may be hidden, is static control with the text) + """ def _findDescendantObject( @@ -80,68 +82,19 @@ def _findDescendantObject( class AppModule(appModuleHandler.AppModule): cachePropertiesByDefault = True - _dataViewControlId: int | None - """Type definition for auto prop '_get__dataViewControlId'""" - - def _get__dataViewControlId(self) -> int | None: - fg = api.getForegroundObject() - dataView = _findDescendantObject(fg.windowHandle, className="wxDataView") - if not dataView: - return None - return dataView.windowControlID - - _sidebarControlId: int | None - """Type definition for auto prop '_get__sidebarControlId'""" - - def _get__sidebarControlId(self) -> int | None: - dataViewControlId = self._dataViewControlId - splitterControlID = dataViewControlId + _WindowControlIdOffsetFromDataView.MAIN_SPLITTER_IDENTIFIER - fg = api.getForegroundObject() - splitterHwnd = windowUtils.findDescendantWindow(fg.windowHandle, controlID=splitterControlID) - sidebarHwnd = winUser.getWindow(splitterHwnd, winUser.GW_HWNDNEXT) - while sidebarHwnd and not ctypes.windll.user32.IsWindowVisible(sidebarHwnd): - sidebarHwnd = winUser.getWindow(sidebarHwnd, winUser.GW_HWNDNEXT) - if not sidebarHwnd: - return None - return winUser.getControlID(sidebarHwnd) - - _isPro: bool - """Type definition for auto prop '_get__isPro'""" - - def _get__isPro(self) -> bool: - """Returns whether this instance of Poedit is a pro version.""" - obj = self._getNVDAObjectForWindowControlIdOffsetFromDataView( - _WindowControlIdOffsetFromDataView.PRO_IDENTIFIER, - ) - return obj is None - - def _getNVDAObjectForWindowControlIdOffsetFromDataView( - self, - windowControlIdOffset: _WindowControlIdOffsetFromDataView, - ) -> Window | None: - fg = api.getForegroundObject() - return _findDescendantObject(fg.windowHandle, self._dataViewControlId + windowControlIdOffset) - - def _getNVDAObjectForWindowControlIdOffsetFromSidebar( + def _getNVDAObjectForWindowControlId( self, - windowControlIdOffset: _WindowControlIdOffsetFromSidebar, + windowControlId: _WindowControlId, ) -> Window | None: fg = api.getForegroundObject() - sidebarControlId = self._sidebarControlId - if sidebarControlId is None: - log.error("Sidebar can not be found") - return None - extraOffset = 0 - if self._isPro: - extraOffset = _WindowControlIdOffsetFromSidebar.PRO_OFFSET - return _findDescendantObject(fg.windowHandle, sidebarControlId + extraOffset + windowControlIdOffset) + return _findDescendantObject(fg.windowHandle, windowControlId) _translatorNotesObj: Window | None """Type definition for auto prop '_get__translatorNotesObj'""" def _get__translatorNotesObj(self) -> Window | None: - return self._getNVDAObjectForWindowControlIdOffsetFromSidebar( - _WindowControlIdOffsetFromSidebar.TRANSLATOR_NOTES, + return self._getNVDAObjectForWindowControlId( + _WindowControlId.NOTES_FOR_TRANSLATOR, ) def _reportControlScriptHelper(self, obj: Window, description: str): @@ -191,9 +144,7 @@ def script_reportAutoCommentsWindow(self, gesture): """Type definition for auto prop '_get__commentObj'""" def _get__commentObj(self) -> Window | None: - return self._getNVDAObjectForWindowControlIdOffsetFromSidebar( - _WindowControlIdOffsetFromSidebar.COMMENT, - ) + return self._getNVDAObjectForWindowControlId(_WindowControlId.TRANSLATOR_COMMENT) @script( description=pgettext( @@ -214,19 +165,19 @@ def script_reportCommentsWindow(self, gesture): pgettext("poedit", "comment"), ) - _oldSourceTextObj: Window | None - """Type definition for auto prop '_get__oldSourceTextObj'""" + _previousSourceTextObj: Window | None + """Type definition for auto prop '_get__previousSourceTextObj'""" - def _get__oldSourceTextObj(self) -> Window | None: - return self._getNVDAObjectForWindowControlIdOffsetFromSidebar( - _WindowControlIdOffsetFromSidebar.OLD_SOURCE_TEXT, + def _get__previousSourceTextObj(self) -> Window | None: + return self._getNVDAObjectForWindowControlId( + _WindowControlId.PREVIOUS_SOURCE_TEXT, ) @script( description=pgettext( "poedit", # Translators: The description of an NVDA command for Poedit. - "Reports the old source text, if any. If pressed twice, presents the text in browse mode", + "Reports the previous source text, if any. If pressed twice, presents the text in browse mode", ), gesture="kb:control+shift+o", category=SCRCAT_POEDIT, @@ -234,25 +185,25 @@ def _get__oldSourceTextObj(self) -> Window | None: ) def script_reportOldSourceText(self, gesture): self._reportControlScriptHelper( - self._oldSourceTextObj, - # Translators: The description of the "old source text" window in poedit. + self._previousSourceTextObj, + # Translators: The description of the "previous source text" window in poedit. # This text is reported when the given window contains no item to report or could not be found. - pgettext("poedit", "old source text"), + pgettext("poedit", "previous source text"), ) - _translationWarningObj: Window | None - """Type definition for auto prop '_get__translationWarningObj'""" + _translationIssueObj: Window | None + """Type definition for auto prop '_get__translationIssueObj'""" - def _get__translationWarningObj(self) -> Window | None: - return self._getNVDAObjectForWindowControlIdOffsetFromDataView( - _WindowControlIdOffsetFromDataView.TRANSLATION_WARNING, + def _get__translationIssueObj(self) -> Window | None: + return self._getNVDAObjectForWindowControlId( + _WindowControlId.TRANSLATION_ISSUE_TEXT, ) @script( description=pgettext( "poedit", # Translators: The description of an NVDA command for Poedit. - "Reports a translation warning, if any. If pressed twice, presents the warning in browse mode", + "Reports a translation issue, if any. If pressed twice, presents the warning in browse mode", ), gesture="kb:control+shift+w", category=SCRCAT_POEDIT, @@ -260,18 +211,18 @@ def _get__translationWarningObj(self) -> Window | None: ) def script_reportTranslationWarning(self, gesture): self._reportControlScriptHelper( - self._translationWarningObj, - # Translators: The description of the "translation warning" window in poedit. + self._translationIssueObj, + # Translators: The description of the "translation issue" window in poedit. # This text is reported when the given window contains no item to report or could not be found. - pgettext("poedit", "translation warning"), + pgettext("poedit", "translation issue"), ) _needsWorkObj: Window | None """Type definition for auto prop '_get__needsWorkObj'""" def _get__needsWorkObj(self) -> Window | None: - obj = self._getNVDAObjectForWindowControlIdOffsetFromDataView( - _WindowControlIdOffsetFromDataView.NEEDS_WORK_SWITCH, + obj = self._getNVDAObjectForWindowControlId( + _WindowControlId.NEEDS_WORK_SWITCH, ) if obj and obj.role == controlTypes.Role.CHECKBOX: return obj @@ -301,19 +252,19 @@ def _get_name(self) -> str: class PoeditListItem(NVDAObject): - _warningControlToReport: _WindowControlIdOffsetFromDataView | None + _warningControlToReport: _WindowControlId | None appModule: AppModule def _get__warningControlToReport(self) -> int | None: - obj = self.appModule._needsWorkObj - if obj and controlTypes.State.CHECKED in obj.states: - return _WindowControlIdOffsetFromDataView.NEEDS_WORK_SWITCH - obj = self.appModule._oldSourceTextObj + obj = self.appModule._previousSourceTextObj if obj and not obj.hasIrrelevantLocation: - return _WindowControlIdOffsetFromSidebar.OLD_SOURCE_TEXT - obj = self.appModule._translationWarningObj + return _WindowControlId.PREVIOUS_SOURCE_TEXT + obj = self.appModule._translationIssueObj if obj and obj.parent and obj.parent.parent and not obj.parent.parent.hasIrrelevantLocation: - return _WindowControlIdOffsetFromDataView.TRANSLATION_WARNING + return _WindowControlId.TRANSLATION_ISSUE_TEXT + obj = self.appModule._needsWorkObj + if obj and controlTypes.State.CHECKED in obj.states: + return _WindowControlId.NEEDS_WORK_SWITCH return None def _get_name(self): @@ -332,9 +283,9 @@ def reportFocus(self): tones.beep(440, 50) return match self._warningControlToReport: - case _WindowControlIdOffsetFromSidebar.OLD_SOURCE_TEXT: + case _WindowControlId.PREVIOUS_SOURCE_TEXT: tones.beep(495, 50) - case _WindowControlIdOffsetFromDataView.TRANSLATION_WARNING: + case _WindowControlId.TRANSLATION_ISSUE_TEXT: tones.beep(550, 50) - case _WindowControlIdOffsetFromDataView.NEEDS_WORK_SWITCH: + case _WindowControlId.NEEDS_WORK_SWITCH: tones.beep(660, 50) diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 0600ff9e52d..32b2fa7c928 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -18,6 +18,8 @@ Cursor routing reliability has been improved, and support for routing keys in Po All lines of cells will now be used when using a multi-line braille display via HID braille. NVDA is no longer unstable after restarting NVDA during an automatic Braille Bluetooth scan. +The minimum required version of Poedit that works with NVDA is now version 3.5. + eSpeak NG has been updated, adding support for the Faroese and Xextan languages. There have also been a number of fixes, including to mouse tracking in Firefox, and the on-demand speech mode. @@ -43,6 +45,7 @@ There have also been a number of fixes, including to mouse tracking in Firefox, * eSpeak NG has been updated to 1.52-dev commit `961454ff`. (#16775) * Added new languages Faroese and Xextan. * When using a multi-line braille display via the standard HID braille driver, all lines of cells will be used. (#16993, @alexmoon) +* The stability of NVDA's Poedit support has been improved with the side effect that the minimum required version of Poedit is now version 3.5. (#16889, @LeonarddeR) ### Bug Fixes diff --git a/user_docs/en/userGuide.md b/user_docs/en/userGuide.md index 1f871343b79..2a3df8cd246 100644 --- a/user_docs/en/userGuide.md +++ b/user_docs/en/userGuide.md @@ -1610,7 +1610,7 @@ Note: The above shortcuts work only with the default formatting string for fooba ### Poedit {#Poedit} -NVDA offers enhanced support for Poedit 3.4 or newer. +NVDA offers enhanced support for Poedit 3.5 or newer.