88
99from enum import IntEnum
1010
11+ import ctypes
1112import api
1213import appModuleHandler
1314import controlTypes
1920from NVDAObjects import NVDAObject
2021from NVDAObjects .window import Window
2122from scriptHandler import getLastScriptRepeatCount , script
23+ from logHandler import log
24+
2225
2326LEFT_TO_RIGHT_EMBEDDING = "\u202a "
2427"""Character often found in translator comments."""
2730SCRCAT_POEDIT = _ ("Poedit" )
2831
2932
30- class _WindowControlIdOffset (IntEnum ):
33+ class _WindowControlIdOffsetFromDataView (IntEnum ):
3134 """Window control ID's are not static, however, the order of ids stays the same.
3235 Therefore, using a wxDataView control in the translations list as a reference,
3336 we can safely calculate control ids accross releases or instances.
3437 This class contains window control id offsets relative to the wxDataView window.
3538 """
3639
3740 PRO_IDENTIFIER = - 10 # This is a button in the free version
38- OLD_SOURCE_TEXT_PRO = 60
39- OLD_SOURCE_TEXT = 65
40- TRANSLATOR_NOTES_PRO = 63
41- TRANSLATOR_NOTES = 68 # 63 in Pro
42- COMMENT_PRO = 66
43- COMMENT = 71
41+ MAIN_SPLITTER_IDENTIFIER = - 2 # The splitter that holds the translation list
4442 TRANSLATION_WARNING = 17
4543 NEEDS_WORK_SWITCH = 21
4644
4745
46+ class _WindowControlIdOffsetFromSidebar (IntEnum ):
47+ """Window control ID's are not static, however, the order of ids stays the same.
48+ Therefore, using the Sidebar window as a reference,
49+ we can safely calculate control ids accross releases or instances.
50+ This class contains window control id offsets relative to the Sidebar window.
51+ Note that this Sidebar window itself is found relative to the dataview's ancestor splitter control.
52+ """
53+
54+ PRO_OFFSET = - 5
55+ OLD_SOURCE_TEXT = 36
56+ TRANSLATOR_NOTES = 39
57+ COMMENT = 42
58+
59+
4860def _findDescendantObject (
4961 parentWindowHandle : int ,
5062 controlId : int | None = None ,
@@ -79,42 +91,58 @@ def _get__dataViewControlId(self) -> int | None:
7991 return None
8092 return dataView .windowControlID
8193
94+ _sidebarControlId : int | None
95+ """Type definition for auto prop '_get__sidebarControlId'"""
96+
97+ def _get__sidebarControlId (self ) -> int | None :
98+ dataViewControlId = self ._dataViewControlId
99+ splitterControlID = dataViewControlId + _WindowControlIdOffsetFromDataView .MAIN_SPLITTER_IDENTIFIER
100+ fg = api .getForegroundObject ()
101+ splitterHwnd = windowUtils .findDescendantWindow (fg .windowHandle , controlID = splitterControlID )
102+ sidebarHwnd = winUser .getWindow (splitterHwnd , winUser .GW_HWNDNEXT )
103+ while sidebarHwnd and not ctypes .windll .user32 .IsWindowVisible (sidebarHwnd ):
104+ sidebarHwnd = winUser .getWindow (sidebarHwnd , winUser .GW_HWNDNEXT )
105+ if not sidebarHwnd :
106+ return None
107+ return winUser .getControlID (sidebarHwnd )
108+
82109 _isPro : bool
83110 """Type definition for auto prop '_get__isPro'"""
84111
85112 def _get__isPro (self ) -> bool :
86113 """Returns whether this instance of Poedit is a pro version."""
87- obj = self ._getNVDAObjectForWindowControlIdOffset (_WindowControlIdOffset .PRO_IDENTIFIER )
114+ obj = self ._getNVDAObjectForWindowControlIdOffsetFromDataView (
115+ _WindowControlIdOffsetFromDataView .PRO_IDENTIFIER
116+ )
88117 return obj is None
89118
90- def _correctWindowControllIdOfset (
91- self ,
92- windowControlIdOffset : _WindowControlIdOffset
93- ) -> _WindowControlIdOffset :
94- """Corrects a _WindowControlIdOffset when a pro version of Poedit is active."""
95- if self ._isPro :
96- match windowControlIdOffset :
97- case _WindowControlIdOffset .OLD_SOURCE_TEXT :
98- return _WindowControlIdOffset .OLD_SOURCE_TEXT_PRO
99- case _WindowControlIdOffset .TRANSLATOR_NOTES :
100- return _WindowControlIdOffset .TRANSLATOR_NOTES_PRO
101- case _WindowControlIdOffset .COMMENT :
102- return _WindowControlIdOffset .COMMENT_PRO
103- return windowControlIdOffset
104-
105- def _getNVDAObjectForWindowControlIdOffset (
119+ def _getNVDAObjectForWindowControlIdOffsetFromDataView (
106120 self ,
107- windowControlIdOffset : _WindowControlIdOffset
121+ windowControlIdOffset : _WindowControlIdOffsetFromDataView
108122 ) -> Window | None :
109123 fg = api .getForegroundObject ()
110124 return _findDescendantObject (fg .windowHandle , self ._dataViewControlId + windowControlIdOffset )
111125
126+ def _getNVDAObjectForWindowControlIdOffsetFromSidebar (
127+ self ,
128+ windowControlIdOffset : _WindowControlIdOffsetFromSidebar
129+ ) -> Window | None :
130+ fg = api .getForegroundObject ()
131+ sidebarControlId = self ._sidebarControlId
132+ if sidebarControlId is None :
133+ log .error ("Sidebar can not be found" )
134+ return None
135+ extraOffset = 0
136+ if self ._isPro :
137+ extraOffset = _WindowControlIdOffsetFromSidebar .PRO_OFFSET
138+ return _findDescendantObject (fg .windowHandle , sidebarControlId + extraOffset + windowControlIdOffset )
139+
112140 _translatorNotesObj : Window | None
113141 """Type definition for auto prop '_get__translatorNotesObj'"""
114142
115143 def _get__translatorNotesObj (self ) -> Window | None :
116- return self ._getNVDAObjectForWindowControlIdOffset (
117- self . _correctWindowControllIdOfset ( _WindowControlIdOffset . TRANSLATOR_NOTES )
144+ return self ._getNVDAObjectForWindowControlIdOffsetFromSidebar (
145+ _WindowControlIdOffsetFromSidebar . TRANSLATOR_NOTES
118146 )
119147
120148 def _reportControlScriptHelper (self , obj : Window , description : str ):
@@ -164,8 +192,8 @@ def script_reportAutoCommentsWindow(self, gesture):
164192 """Type definition for auto prop '_get__commentObj'"""
165193
166194 def _get__commentObj (self ) -> Window | None :
167- return self ._getNVDAObjectForWindowControlIdOffset (
168- self . _correctWindowControllIdOfset ( _WindowControlIdOffset . COMMENT )
195+ return self ._getNVDAObjectForWindowControlIdOffsetFromSidebar (
196+ _WindowControlIdOffsetFromSidebar . COMMENT
169197 )
170198
171199 @script (
@@ -191,8 +219,8 @@ def script_reportCommentsWindow(self, gesture):
191219 """Type definition for auto prop '_get__oldSourceTextObj'"""
192220
193221 def _get__oldSourceTextObj (self ) -> Window | None :
194- return self ._getNVDAObjectForWindowControlIdOffset (
195- self . _correctWindowControllIdOfset ( _WindowControlIdOffset . OLD_SOURCE_TEXT )
222+ return self ._getNVDAObjectForWindowControlIdOffsetFromSidebar (
223+ _WindowControlIdOffsetFromSidebar . OLD_SOURCE_TEXT
196224 )
197225
198226 @script (
@@ -217,7 +245,9 @@ def script_reportOldSourceText(self, gesture):
217245 """Type definition for auto prop '_get__translationWarningObj'"""
218246
219247 def _get__translationWarningObj (self ) -> Window | None :
220- return self ._getNVDAObjectForWindowControlIdOffset (_WindowControlIdOffset .TRANSLATION_WARNING )
248+ return self ._getNVDAObjectForWindowControlIdOffsetFromDataView (
249+ _WindowControlIdOffsetFromDataView .TRANSLATION_WARNING
250+ )
221251
222252 @script (
223253 description = pgettext (
@@ -241,7 +271,9 @@ def script_reportTranslationWarning(self, gesture):
241271 """Type definition for auto prop '_get__needsWorkObj'"""
242272
243273 def _get__needsWorkObj (self ) -> Window | None :
244- obj = self ._getNVDAObjectForWindowControlIdOffset (_WindowControlIdOffset .NEEDS_WORK_SWITCH )
274+ obj = self ._getNVDAObjectForWindowControlIdOffsetFromDataView (
275+ _WindowControlIdOffsetFromDataView .NEEDS_WORK_SWITCH
276+ )
245277 if obj and obj .role == controlTypes .Role .CHECKBOX :
246278 return obj
247279 return None
@@ -270,19 +302,19 @@ def _get_name(self) -> str:
270302
271303
272304class PoeditListItem (NVDAObject ):
273- _warningControlToReport : _WindowControlIdOffset | None
305+ _warningControlToReport : _WindowControlIdOffsetFromDataView | None
274306 appModule : AppModule
275307
276- def _get__warningControlToReport (self ) -> _WindowControlIdOffset | None :
308+ def _get__warningControlToReport (self ) -> int | None :
277309 obj = self .appModule ._needsWorkObj
278310 if obj and controlTypes .State .CHECKED in obj .states :
279- return _WindowControlIdOffset .NEEDS_WORK_SWITCH
311+ return _WindowControlIdOffsetFromDataView .NEEDS_WORK_SWITCH
280312 obj = self .appModule ._oldSourceTextObj
281313 if obj and not obj .hasIrrelevantLocation :
282- return _WindowControlIdOffset .OLD_SOURCE_TEXT
314+ return _WindowControlIdOffsetFromSidebar .OLD_SOURCE_TEXT
283315 obj = self .appModule ._translationWarningObj
284316 if obj and obj .parent and obj .parent .parent and not obj .parent .parent .hasIrrelevantLocation :
285- return _WindowControlIdOffset .TRANSLATION_WARNING
317+ return _WindowControlIdOffsetFromDataView .TRANSLATION_WARNING
286318 return None
287319
288320 def _get_name (self ):
@@ -301,9 +333,9 @@ def reportFocus(self):
301333 tones .beep (440 , 50 )
302334 return
303335 match self ._warningControlToReport :
304- case _WindowControlIdOffset .OLD_SOURCE_TEXT :
336+ case _WindowControlIdOffsetFromSidebar .OLD_SOURCE_TEXT :
305337 tones .beep (495 , 50 )
306- case _WindowControlIdOffset .TRANSLATION_WARNING :
338+ case _WindowControlIdOffsetFromDataView .TRANSLATION_WARNING :
307339 tones .beep (550 , 50 )
308- case _WindowControlIdOffset .NEEDS_WORK_SWITCH :
340+ case _WindowControlIdOffsetFromDataView .NEEDS_WORK_SWITCH :
309341 tones .beep (660 , 50 )
0 commit comments