Changeset 2356

Show
Ignore:
Timestamp:
08/31/08 23:54:12 (4 months ago)
Author:
bzr
Message:

Merging changes from documentFormatting branch:
*The ITextDocument object model is now used to provide access to richedit controls if they support it. This fixes some character set issues, plus it allows sayAll to read by sentence, rather than by line, in these controls.
*Re-implemented support for announcement of document formatting, such as fontName, fontSize etc, also including announcement of field types in virtualBuffers such as links and headings. In general, the user shouldn't notice too much of a difference, except for some possible performance improvements. However, the new implementation was necessary so that its possible in future to add formatting to the virtualBuffer library backends, so that NVDA will be able to report things such as font name/size/attributes changes in virtualBuffers for Firefox etc.
*Added checkboxes for controling the announcement of links, headings, lists, and block quotes, to the document formatting settings dialog. These checkboxes are now how you can control the announcement of these elements in virtualBuffers, and where ever they also may appear in documents. Note that virtualBuffers for Internet Explorer etc, are still only affected by the checkboxes in the virtualBuffer settings dialog.
*Added formatting support for IAccessible2. This means you can now ask for formatting with nvda+f, or listen to formatting automatically (if its turned on) in edit fields of Firefox or Thunderbird, and other IA2 applications.
*Added a report spelling errors checkbox to the document formatting settings dialog. So far NVDA can announce spelling errors in Mozilla Gecko applications.

Location:
trunk
Files:
1 added
16 modified

Legend:

Unmodified
Added
Removed
  • trunk

    • Property bzr:revision-info
      •  

        old new  
        1 timestamp: 2008-08-25 15:50:50.964999914 +1000 
        2 committer: James Teh <jamie@jantrid.net> 
         1timestamp: 2008-09-01 09:43:41.051000118 +1000 
         2committer: Michael Curran <mick@kulgan.net> 
        33properties:  
        44        branch-nick: main 
        5         rebase-of: jamie@jantrid.net-20080825055050-xv211pssgq6gt5j4 
    • Property bzr:ancestry:v3-list-QlpoOTFBWSZTWbrL2vUAAB1VgAAQABCAQDrrnqAgAFCgaaGRkxBoTIJ6mmaNRwhndFAoNhZjh_YY4a01fOg1ulgNNC2UrzPdXXEnDpX8XckU4UJC6y9r1A..
      •  

        old new  
        99jamie@jantrid.net-20080702061732-274iwmap8bkwbp8b 
        1010jamie@jantrid.net-20080810101432-te9chzpil51jwjtd 
         11mick@kulgan.net-20080830094018-0azn22n453on23ve 
    • Property bzr:revision-id:v3-list-QlpoOTFBWSZTWbrL2vUAAB1VgAAQABCAQDrrnqAgAFCgaaGRkxBoTIJ6mmaNRwhndFAoNhZjh_YY4a01fOg1ulgNNC2UrzPdXXEnDpX8XckU4UJC6y9r1A..
      •  

        old new  
        1781782147 jamie@jantrid.net-20080812071342-5fqd45cc29z5ugh6 
        1791792152 jamie@jantrid.net-20080825055050-hyorj43ch7hh1iht 
         1802155 mick@kulgan.net-20080831234341-iqj7xxt8ff8vy0qb 
    • Property bzr:file-ids
      •  

        old new  
        1 dependencies.txt        46@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:dependencies.txt 
         1source/IAccessibleHandler.py    267@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FIAccessibleHandler.py 
         2source/NVDAObjects/IAccessible/__init__.py      683@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FNVDAObjects%2FIAccessible%2F__init__.py 
         3source/NVDAObjects/IAccessible/edit.py  885@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FNVDAObjects%2FIAccessible%2Fedit.py 
         4source/NVDAObjects/IAccessible/scintilla.py     829@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FNVDAObjects%2FIAccessible%2Fscintilla.py 
         5source/NVDAObjects/IAccessible/winword.py       683@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FNVDAObjects%2FIAccessible%2Fwinword.py 
         6source/NVDAObjects/__init__.py  683@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FNVDAObjects%2F__init__.py 
         7source/XMLFormatting.py xmlfields.py-20080814010608-6uk350dgitsm0dyn-1 
         8source/appModules/_default.py   92@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FappModules%2F_default.py 
         9source/config/__init__.py       46@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2Fconfig%2F__init__.py 
         10source/cursorManager.py cursormanager.py-20080207040300-ipt2bssoovrlbxu3-1 
         11source/gui/settingsDialogs.py   299@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2Fgui%2FsettingsDialogs.py 
         12source/sayAllHandler.py 329@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FsayAllHandler.py 
         13source/speech.py        503@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2Fspeech.py 
         14source/textHandler.py   1028@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FtextHandler.py 
         15source/virtualBuffers/__init__.py       1675@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FvirtualBuffers%2F__init__.py 
         16source/virtualBuffers/gecko_ia2.py      1694@dbe06fc7-9119-0410-a01d-9dbf589ecbba:trunk:source%2FvirtualBuffers%2Fgecko_ia2.py 
    • Property bzr:text-parents
      •  

        old new  
         1source/IAccessibleHandler.py    jamie@jantrid.net-20080826215455-s3rsvr03h3y09l0b 
         2source/NVDAObjects/IAccessible/__init__.py      mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         3source/NVDAObjects/IAccessible/edit.py  mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         4source/NVDAObjects/IAccessible/scintilla.py     jamie@jantrid.net-20080829050819-l2uzzylzsk10ipg9 
         5source/NVDAObjects/IAccessible/winword.py       mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         6source/NVDAObjects/__init__.py  mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         7source/XMLFormatting.py mick@kulgan.net-20080819081222-mas0aaknel9mjngn 
         8source/appModules/_default.py   mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         9source/config/__init__.py       mick@kulgan.net-20080830094018-0azn22n453on23ve 
         10source/cursorManager.py jamie@jantrid.net-20080823064206-97fsdw2121jbi9vn 
         11source/gui/settingsDialogs.py   mick@kulgan.net-20080830094018-0azn22n453on23ve 
         12source/sayAllHandler.py jamie@jantrid.net-20080822052649-kf6dp2pz4dcb33f6 
         13source/textHandler.py   mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         14source/virtualBuffers/__init__.py       mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
         15source/virtualBuffers/gecko_ia2.py      mick@kulgan.net-20080829043527-6p313ou2ktvxu73s 
  • trunk/source/IAccessibleHandler.py

    r2248 r2356  
    10351035                textList.append(t) 
    10361036        return "".join(textList).replace('  ',' ') 
     1037 
     1038def splitIA2Attribs(attribsString): 
     1039        """Split an IAccessible2 attributes string into a dict of attribute keys and values. 
     1040        An invalid attributes string does not cause an error, but strange results may be returned. 
     1041        Subattributes are handled. Subattribute keys and values are placed into a dict which becomes the value of the attribute. 
     1042        @param attribsString: The IAccessible2 attributes string to convert. 
     1043        @type attribsString: str 
     1044        @return: A dict of the attribute keys and values, where values are strings or dicts. 
     1045        @rtype: {str: str or {str: str}} 
     1046        """ 
     1047        attribsDict = {} 
     1048        tmp = "" 
     1049        key = "" 
     1050        subkey = "" 
     1051        subattr = {} 
     1052        inEscape = False 
     1053        for char in attribsString: 
     1054                if inEscape: 
     1055                        tmp += char 
     1056                        inEscape = False 
     1057                elif char == "\\": 
     1058                        inEscape = True 
     1059                elif char == ":": 
     1060                        # We're about to move on to the value, so save the key and clear tmp. 
     1061                        key = tmp 
     1062                        tmp = "" 
     1063                elif char == "=": 
     1064                        # This is a subattribute. 
     1065                        # Save the subattribute key and clear tmp, ready for the value. 
     1066                        subkey = tmp 
     1067                        tmp = "" 
     1068                elif char == ",": 
     1069                        # We're about to move on to a new subattribute. 
     1070                        # Add this subattribute key/value pair to the dict. 
     1071                        if subkey: 
     1072                                subattr[subkey] = tmp 
     1073                                subkey = "" 
     1074                                tmp = "" 
     1075                elif char == ";": 
     1076                        # We're about to move on to a new attribute. 
     1077                        if subkey: 
     1078                                # This attribute had subattributes. 
     1079                                # Add the last subattribute key/value pair to the dict. 
     1080                                subattr[subkey] = tmp 
     1081                                # Add the key/subattribute pair to the dict. 
     1082                                attribsDict[key] = subattr 
     1083                                subkey = "" 
     1084                                subattr = {} 
     1085                        elif key: 
     1086                                # Add this key/value pair to the dict. 
     1087                                attribsDict[key] = tmp 
     1088                        key = "" 
     1089                        tmp = "" 
     1090                else: 
     1091                        tmp += char 
     1092        # If there was no trailing semi-colon, we need to handle the last attribute. 
     1093        if subkey: 
     1094                # This attribute had subattributes. 
     1095                # Add the last subattribute key/value pair to the dict. 
     1096                subattr[subkey] = tmp 
     1097                # Add the key/subattribute pair to the dict. 
     1098                attribsDict[key] = subattr 
     1099        elif key: 
     1100                # Add this key/value pair to the dict. 
     1101                attribsDict[key] = tmp 
     1102        return attribsDict 
  • trunk/source/NVDAObjects/IAccessible/__init__.py

    r2327 r2356  
    77import weakref 
    88import re 
     9from comtypes import COMError 
    910import struct 
    1011import os 
     
    133134                except: 
    134135                        return "" 
     136 
     137        def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True): 
     138                try: 
     139                        startOffset,endOffset,attribsString=self.obj.IAccessibleTextObject.attributes(offset) 
     140                except COMError: 
     141                        log.debugWarning("could not get attributes",exc_info=True) 
     142                        return textHandler.FormatField(),(self._startOffset,self._endOffset) 
     143                formatField=textHandler.FormatField() 
     144                if not attribsString and offset>0: 
     145                        try: 
     146                                attribsString=self.obj.IAccessibleTextObject.attributes(offset-1)[2] 
     147                        except COMError: 
     148                                pass 
     149                if attribsString: 
     150                        formatField.update(IAccessibleHandler.splitIA2Attribs(attribsString)) 
     151                try: 
     152                        textAlign=formatField.pop("text-align") 
     153                except KeyError: 
     154                        textAlign=None 
     155                if textAlign: 
     156                        if "right" in textAlign: 
     157                                textAlign="right" 
     158                        elif "center" in textAlign: 
     159                                textAlign="center" 
     160                        elif "justify" in textAlign: 
     161                                textAlign="justify" 
     162                        formatField["text-align"]=textAlign 
     163                try: 
     164                        fontWeight=formatField.pop("font-weight") 
     165                except KeyError: 
     166                        fontWeight=None 
     167                if fontWeight is not None and (fontWeight.lower()=="bold" or (fontWeight.isdigit() and int(fontWeight)>=700)): 
     168                        formatField["bold"]=True 
     169                else: 
     170                        formatField["bold"]=False 
     171                try: 
     172                        fontStyle=formatField.pop("font-style") 
     173                except KeyError: 
     174                        fontStyle=None 
     175                if fontStyle is not None and fontStyle.lower()=="italic": 
     176                        formatField["italic"]=True 
     177                else: 
     178                        formatField["italic"]=False 
     179                try: 
     180                        invalid=formatField.pop("invalid") 
     181                except KeyError: 
     182                        invalid=None 
     183                if invalid and invalid.lower()=="spelling": 
     184                        formatField["invalid-spelling"]=True 
     185                return formatField,(startOffset,endOffset) 
    135186 
    136187        def _getCharacterOffsets(self,offset): 
  • trunk/source/NVDAObjects/IAccessible/edit.py

    r2190 r2356  
    1414import comInterfaces.tom 
    1515from logHandler import log 
     16import config 
    1617import speech 
    1718import winKernel 
     
    173174                return offset 
    174175 
    175         def _getFormatAndOffsets(self,offset,includes=set(),excludes=set()): 
    176                 formatList,start,end=super(EditTextInfo,self)._getFormatAndOffsets(offset,includes=includes,excludes=excludes) 
    177                 if self.obj.editAPIVersion>=1: 
    178                         oldSel=self._getSelectionOffsets() 
    179                         if oldSel[0]!=offset and oldSel[1]!=offset: 
    180                                 self._setSelectionOffsets(offset,offset) 
    181                         if self.obj.isWindowUnicode: 
    182                                 charFormatStruct=CharFormat2WStruct 
    183                         else: 
    184                                 charFormatStruct=CharFormat2AStruct 
    185                         charFormat=charFormatStruct() 
    186                         charFormat.cbSize=ctypes.sizeof(charFormatStruct) 
    187                         processHandle=self.obj.editProcessHandle 
    188                         internalCharFormat=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charFormat),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) 
    189                         winKernel.writeProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None) 
    190                         winUser.sendMessage(self.obj.windowHandle,EM_GETCHARFORMAT,SCF_SELECTION, internalCharFormat) 
    191                         winKernel.readProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None) 
    192                         winKernel.virtualFreeEx(processHandle,internalCharFormat,0,winKernel.MEM_RELEASE) 
    193                         if textHandler.isFormatEnabled(controlTypes.ROLE_FONTNAME,includes=includes,excludes=excludes): 
    194                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_CHANGE,textHandler.Format(role=controlTypes.ROLE_FONTNAME,value=charFormat.szFaceName)) 
    195                                 formatList.append(f) 
    196                         if textHandler.isFormatEnabled(controlTypes.ROLE_FONTSIZE,includes=includes,excludes=excludes): 
    197                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_CHANGE,textHandler.Format(role=controlTypes.ROLE_FONTSIZE,value=charFormat.yHeight/20)) 
    198                                 formatList.append(f) 
    199                         if (charFormat.dwEffects&CFM_BOLD) and textHandler.isFormatEnabled(controlTypes.ROLE_BOLD,includes=includes,excludes=excludes): 
    200                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_SWITCHON,textHandler.Format(role=controlTypes.ROLE_BOLD)) 
    201                                 formatList.append(f) 
    202                         if (charFormat.dwEffects&CFM_ITALIC) and textHandler.isFormatEnabled(controlTypes.ROLE_ITALIC,includes=includes,excludes=excludes): 
    203                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_SWITCHON,textHandler.Format(role=controlTypes.ROLE_ITALIC)) 
    204                                 formatList.append(f) 
    205                         if (charFormat.dwEffects&CFM_UNDERLINE) and textHandler.isFormatEnabled(controlTypes.ROLE_UNDERLINE,includes=includes,excludes=excludes): 
    206                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_SWITCHON,textHandler.Format(role=controlTypes.ROLE_UNDERLINE)) 
    207                                 formatList.append(f) 
    208                         if (charFormat.dwEffects&CFE_SUBSCRIPT) and textHandler.isFormatEnabled(controlTypes.ROLE_SUBSCRIPT,includes=includes,excludes=excludes): 
    209                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_SWITCHON,textHandler.Format(role=controlTypes.ROLE_SUBSCRIPT)) 
    210                                 formatList.append(f) 
    211                         if (charFormat.dwEffects&CFE_SUPERSCRIPT) and textHandler.isFormatEnabled(controlTypes.ROLE_SUPERSCRIPT,includes=includes,excludes=excludes): 
    212                                 f=textHandler.FormatCommand(textHandler.FORMAT_CMD_SWITCHON,textHandler.Format(role=controlTypes.ROLE_SUPERSCRIPT)) 
    213                                 formatList.append(f) 
    214                         if oldSel[0]!=offset and oldSel[1]!=offset: 
    215                                 self._setSelectionOffsets(oldSel[0],oldSel[1]) 
    216                 return (formatList,start,end) 
    217  
    218  
    219  
    220  
     176        def _getCharFormat(self,offset): 
     177                oldSel=self._getSelectionOffsets() 
     178                if oldSel!=(offset,offset+1): 
     179                        self._setSelectionOffsets(offset,offset+1) 
     180                if self.obj.isWindowUnicode: 
     181                        charFormatStruct=CharFormat2WStruct 
     182                else: 
     183                        charFormatStruct=CharFormat2AStruct 
     184                charFormat=charFormatStruct() 
     185                charFormat.cbSize=ctypes.sizeof(charFormatStruct) 
     186                processHandle=self.obj.editProcessHandle 
     187                internalCharFormat=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charFormat),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) 
     188                winKernel.writeProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None) 
     189                winUser.sendMessage(self.obj.windowHandle,EM_GETCHARFORMAT,SCF_SELECTION, internalCharFormat) 
     190                winKernel.readProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None) 
     191                winKernel.virtualFreeEx(processHandle,internalCharFormat,0,winKernel.MEM_RELEASE) 
     192                if oldSel!=(offset,offset+1): 
     193                        self._setSelectionOffsets(oldSel[0],oldSel[1]) 
     194                return charFormat 
     195 
     196        def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True): 
     197                #Basic edit fields do not support formatting at all 
     198                if self.obj.editAPIVersion<1: 
     199                        return super(EditTextInfo,self)._getFormatFieldAndOffsets(offset,formatConfig,calculateOffsets=calculateOffsets) 
     200                if calculateOffsets: 
     201                        startOffset,endOffset=self._getWordOffsets(offset) 
     202                else: 
     203                        startOffset,endOffset=self._startOffset,self._endOffset 
     204                formatField=textHandler.FormatField() 
     205                charFormat=None 
     206                if formatConfig["reportFontName"]: 
     207                        if charFormat is None: charFormat=self._getCharFormat(offset) 
     208                        formatField["font-name"]=charFormat.szFaceName 
     209                if formatConfig["reportFontSize"]: 
     210                        if charFormat is None: charFormat=self._getCharFormat(offset) 
     211                        formatField["font-size"]="%spt"%(charFormat.yHeight/20) 
     212                if formatConfig["reportFontAttributes"]: 
     213                        if charFormat is None: charFormat=self._getCharFormat(offset) 
     214                        formatField["bold"]=bool(charFormat.dwEffects&CFM_BOLD) 
     215                        formatField["italic"]=bool(charFormat.dwEffects&CFM_ITALIC) 
     216                        formatField["underline"]=bool(charFormat.dwEffects&CFM_UNDERLINE) 
     217                        if charFormat.dwEffects&CFE_SUBSCRIPT: 
     218                                formatField["text-position"]="sub" 
     219                        elif charFormat.dwEffects&CFE_SUPERSCRIPT: 
     220                                formatField["text-position"]="super" 
     221                if formatConfig["reportLineNumber"]: 
     222                        formatField["line-number"]=self._getLineNumFromOffset(offset)+1 
     223                return formatField,(startOffset,endOffset) 
    221224 
    222225        def _getSelectionOffsets(self): 
     
    275278                return winUser.sendMessage(self.obj.windowHandle,EM_GETLINECOUNT,0,0) 
    276279 
    277         def _getTextRangeWithEmbeddedObjects(self,start,end): 
    278                 ptr=ctypes.POINTER(comInterfaces.tom.ITextDocument)() 
    279                 ctypes.windll.oleacc.AccessibleObjectFromWindow(self.obj.windowHandle,-16,ctypes.byref(ptr._iid_),ctypes.byref(ptr)) 
    280                 r=ptr.Range(self._startOffset,self._endOffset) 
    281                 bufText=r.text 
    282                 if bufText is None: 
    283                         bufText="" 
    284                 newTextList=[] 
    285                 for offset in range(len(bufText)): 
    286                         if ord(bufText[offset])==0xfffc: 
    287                                 embedRange=ptr.Range(start+offset,start+offset) 
    288                                 o=embedRange.GetEmbeddedObject() 
    289                                 o=o.QueryInterface(oleTypes.IOleObject) 
    290                                 dataObj=o.GetClipboardData(0) 
    291                                 dataObj=pythoncom._univgw.interface(hash(dataObj),pythoncom.IID_IDataObject) 
    292                                 format=(win32clipboard.CF_UNICODETEXT, None, pythoncom.DVASPECT_CONTENT, -1, pythoncom.TYMED_HGLOBAL) 
    293                                 medium=dataObj.GetData(format) 
    294                                 buf=ctypes.create_string_buffer(medium.data) 
    295                                 buf=ctypes.cast(buf,ctypes.c_wchar_p) 
    296                                 newTextList.append(buf.value) 
    297                         else: 
    298                                 newTextList.append(bufText[offset]) 
    299                 return "".join(newTextList) 
    300  
    301280        def _getTextRange(self,start,end): 
    302281                if self.obj.editAPIVersion>=2: 
    303                         if self.obj.editAPIHasITextDocument: 
    304                                 return self._getTextRangeWithEmbeddedObjects(start,end) 
    305282                        bufLen=((end-start)+1)*2 
    306283                        if self.obj.isWindowUnicode: 
     
    410387class ITextDocumentTextInfo(textHandler.TextInfo): 
    411388 
     389        def _getFormatFieldAtRange(self,range,formatConfig): 
     390                formatField=textHandler.FormatField() 
     391                fontObj=None 
     392                paraFormatObj=None 
     393                if formatConfig["reportAlignment"]: 
     394                        if not paraFormatObj: paraFormatObj=range.para 
     395                        alignment=paraFormatObj.alignment 
     396                        if alignment==comInterfaces.tom.tomAlignLeft: 
     397                                formatField["text-align"]="left" 
     398                        elif alignment==comInterfaces.tom.tomAlignCenter: 
     399                                formatField["text-align"]="center" 
     400                        elif alignment==comInterfaces.tom.tomAlignRight: 
     401                                formatField["text-align"]="right" 
     402                        elif alignment==comInterfaces.tom.tomAlignJustify: 
     403                                formatField["text-align"]="justify" 
     404                if formatConfig["reportLineNumber"]: 
     405                        formatField["line-number"]=range.getIndex(comInterfaces.tom.tomLine) 
     406                if formatConfig["reportFontName"]: 
     407                        if not fontObj: fontObj=range.font 
     408                        formatField["font-name"]=fontObj.name 
     409                if formatConfig["reportFontSize"]: 
     410                        if not fontObj: fontObj=range.font 
     411                        formatField["font-size"]="%spt"%fontObj.size 
     412                if formatConfig["reportFontAttributes"]: 
     413                        if not fontObj: fontObj=range.font 
     414                        formatField["bold"]=bool(fontObj.bold) 
     415                        formatField["italic"]=bool(fontObj.italic) 
     416                        formatField["underline"]=bool(fontObj.underline) 
     417                        if fontObj.superscript: 
     418                                formatField["text-position"]="super" 
     419                        elif fontObj.subscript: 
     420                                formatField["text-position"]="sub" 
     421                return formatField 
     422 
     423        def _expandFormatRange(self,range,formatConfig): 
     424                startLimit=self._rangeObj.start 
     425                endLimit=self._rangeObj.end 
     426                chunkRange=range.duplicate 
     427                if formatConfig["reportLineNumber"]: 
     428                        chunkRange.expand(comInterfaces.tom.tomLine) 
     429                else: 
     430                        chunkRange.expand(comInterfaces.tom.tomParagraph) 
     431                chunkStart=chunkRange.start 
     432                chunkEnd=chunkRange.end 
     433                if startLimit<chunkStart: 
     434                        startLimit=chunkStart 
     435                if endLimit>chunkEnd: 
     436                        endLimit=chunkEnd 
     437                #range.moveEnd(comInterfaces.tom.tomCharFormat,1) 
     438                range.expand(comInterfaces.tom.tomCharFormat) 
     439                if range.end>endLimit: 
     440                        range.end=endLimit 
     441                if range.start<startLimit: 
     442                        range.start=startLimit 
     443 
     444        def _getTextAtRange(self,rangeObj): 
     445                embedRangeObj=None 
     446                bufText=rangeObj.text 
     447                if bufText is None: 
     448                        bufText="" 
     449                newTextList=[] 
     450                start=rangeObj.start 
     451                for offset in range(len(bufText)): 
     452                        if ord(bufText[offset])==0xfffc: 
     453                                if embedRangeObj is None: embedRangeObj=rangeObj.duplicate 
     454                                embedRangeObj.setRange(start+offset,start+offset) 
     455                                o=embedRangeObj.GetEmbeddedObject() 
     456                                #Fetch a description for this object 
     457                                try: 
     458                                        o=o.QueryInterface(oleTypes.IOleObject) 
     459                                        dataObj=o.GetClipboardData(0) 
     460                                        dataObj=pythoncom._univgw.interface(hash(dataObj),pythoncom.IID_IDataObject) 
     461                                        format=(win32clipboard.CF_UNICODETEXT, None, pythoncom.DVASPECT_CONTENT, -1, pythoncom.TYMED_HGLOBAL) 
     462                                        medium=dataObj.GetData(format) 
     463                                        buf=ctypes.create_string_buffer(medium.data) 
     464                                        buf=ctypes.cast(buf,ctypes.c_wchar_p) 
     465                                        label=buf.value 
     466                                except comtypes.COMError: 
     467                                        label=_("unknown") 
     468                                newTextList.append(_("%s embedded object")%label) 
     469                        else: 
     470                                newTextList.append(bufText[offset]) 
     471                return "".join(newTextList) 
     472 
    412473        def __init__(self,obj,position,_rangeObj=None): 
    413474                super(ITextDocumentTextInfo,self).__init__(obj,position) 
     
    436497                        raise NotImplementedError("position: %s"%position) 
    437498 
     499        def getInitialFields(self,formatConfig=None): 
     500                if not formatConfig: 
     501                        formatConfig=config.conf["documentFormatting"] 
     502                range=self._rangeObj.duplicate 
     503                range.collapse(True) 
     504                range.expand(comInterfaces.tom.tomCharacter) 
     505                return [self._getFormatFieldAtRange(range,formatConfig)] 
     506 
     507        def getTextWithFields(self,formatConfig=None): 
     508                if not formatConfig: 
     509                        formatConfig=config.conf["documentFormatting"] 
     510                if not formatConfig["detectFormatAfterCursor"]: 
     511                        return [self._getTextAtRange(self._rangeObj)] 
     512                commandList=[] 
     513                endLimit=self._rangeObj.end 
     514                range=self._rangeObj.duplicate 
     515                range.collapse(True) 
     516                hasLoopedOnce=False 
     517                while range.end<endLimit: 
     518                        self._expandFormatRange(range,formatConfig) 
     519                        if hasLoopedOnce: 
     520                                commandList.append(textHandler.FieldCommand("formatChange",self._getFormatFieldAtRange(range,formatConfig))) 
     521                        else: 
     522                                hasLoopedOnce=True 
     523                        commandList.append(self._getTextAtRange(range)) 
     524                        end=range.end 
     525                        range.start=end 
     526                        #Trying to set the start past the end of the document forces both start and end back to the previous offset, so catch this 
     527                        if range.end<end: 
     528                                break 
     529                return commandList 
     530 
    438531        def expand(self,unit): 
    439532                if unit in NVDAUnitsToITextDocumentUnits: 
     
    492585 
    493586        def _get_text(self): 
    494                 return self._rangeObj.text 
     587                return self._getTextAtRange(self._rangeObj) 
    495588 
    496589        def move(self,unit,direction,endPoint=None): 
     
    522615        editAPIVersion=0 
    523616        editAPIUnicode=True 
    524         editAPIHasITextDocument=False 
    525617        editValueUnit=textHandler.UNIT_LINE 
    526618 
    527619        def __init__(self,*args,**kwargs): 
    528620                super(Edit,self).__init__(*args,**kwargs) 
    529                 #For now disable ITextDocument support 
    530                 if False and self.editAPIVersion>1 and self.ITextDocumentObject: 
     621                if self.editAPIVersion>1 and self.ITextDocumentObject: 
    531622                        self.TextInfo=ITextDocumentTextInfo 
    532623                else: 
  • trunk/source/NVDAObjects/IAccessible/scintilla.py

    r2133 r2356  
    66import globalVars 
    77import controlTypes 
     8import config 
    89from . import IAccessible  
    910from .. import NVDAObjectTextInfo 
     
    6162                return winUser.sendMessage(self.obj.windowHandle,SCI_POSITIONFROMPOINT,x,y) 
    6263 
    63         def _getFormatAndOffsets(self,offset,includes=set(),excludes=set()): 
    64                 formatList,start,end=super(ScintillaTextInfo,self)._getFormatAndOffsets(offset,includes=includes,excludes=excludes) 
    65                 oldSel=self._getSelectionOffsets() 
    66                 if oldSel[0]!=offset and oldSel[1]!=offset: 
    67                         self._setSelectionOffsets(offset,offset) 
     64        def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True): 
    6865                style=winUser.sendMessage(self.obj.windowHandle,SCI_GETSTYLEAT,offset,0) 
    69 #To get font name, We need to allocate memory with in Scintilla's process, and then copy it out 
    70                 fontNameBuf=ctypes.create_string_buffer(32) 
    71                 internalBuf=winKernel.virtualAllocEx(self.obj.processHandle,None,len(fontNameBuf),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) 
    72                 winUser.sendMessage(self.obj.windowHandle,SCI_STYLEGETFONT,style, internalBuf) 
    73                 winKernel.readProcessMemory(self.obj.processHandle,internalBuf,fontNameBuf,len(fontNameBuf),None) 
    74                 winKernel.virtualFreeEx(self.obj.processHandle,internalBuf,0,winKernel.MEM_RELEASE) 
    75                 if textHandler.isFormatEnabled(controlTypes.ROLE_FONTNAME,includes=includes,excludes=excludes): 
    76                         f=textHandler.FormatCommand(textHandler.FORMAT_CMD_CHANGE,textHandler.Format(role=controlTypes.ROLE_FONTNAME,value=fontNameBuf.value)) 
    77                         formatList.append(f) 
    78                 if textHandler.isFormatEnabled(controlTypes.ROLE_FONTSIZE,includes=includes,excludes=excludes): 
    79                         f=textHandler.FormatCommand(textHandler.FORMAT_CMD_CHANGE,textHandler.Format(role=controlTypes.ROLE_FONTSIZE,value=winUser.sendMessage(self.obj.windowHandle,SCI_STYLEGETSIZE,style,0)))