Permalink
Browse files

In Microsoft Excel, NVDA now reports when a cell has overflowing or c…

…ropped content.

Fixes #3040.
  • Loading branch information...
siddhartha-iitd authored and jcsteh committed Apr 14, 2015
1 parent 6816ad8 commit 785fc4ec2700c444ac3360a92384edc8d84654b6
Showing with 116 additions and 1 deletion.
  1. +109 −1 source/NVDAObjects/window/excel.py
  2. +6 −0 source/controlTypes.py
  3. +1 −0 user_docs/en/changes.t2t
@@ -27,6 +27,7 @@
from . import Window
from .. import NVDAObjectTextInfo
import scriptHandler
import ctypes
xlCenter=-4108
xlJustify=-4130
@@ -35,7 +36,7 @@
xlDistributed=-4117
xlBottom=-4107
xlTop=-4160
xlCellWidthUnitToPixels = 7.5919335705812574139976275207592
alignmentLabels={
xlCenter:"center",
xlJustify:"justify",
@@ -561,8 +562,115 @@ def _get_states(self):
comment=None
if comment:
states.add(controlTypes.STATE_HASCOMMENT)
if self._overlapInfo is not None:
if self._overlapInfo['obscuredFromRightBy'] > 0:
states.add(controlTypes.STATE_CROPPED)
if self._overlapInfo['obscuringRightBy'] > 0:
states.add(controlTypes.STATE_OVERFLOWING)
return states
def getCellWidthAndTextWidth(self):
#handle to Device Context
hDC = ctypes.windll.user32.GetDC(self.windowHandle)
tempDC = ctypes.windll.gdi32.CreateCompatibleDC(hDC)
ctypes.windll.user32.ReleaseDC(self.windowHandle, hDC)
#Compatible Bitmap for current Device Context
hBMP = ctypes.windll.gdi32.CreateCompatibleBitmap(tempDC, 1, 1)
#handle to the bitmap object
hOldBMP = ctypes.windll.gdi32.SelectObject(tempDC, hBMP)
#Pass Device Context and LOGPIXELSX, the horizontal resolution in pixels per unit inch
deviceCaps = ctypes.windll.gdi32.GetDeviceCaps(tempDC, 88)
#Fetching Font Size and Weight information
iFontSize = self.excelCellObject.Font.Size
iFontSize = 11 if iFontSize is None else int(iFontSize)
iFontSize = ctypes.c_int(iFontSize)
iFontSize = ctypes.windll.kernel32.MulDiv(iFontSize, deviceCaps, 72)
#Font Weight for Bold FOnt is 700 and for normal font it's 400
iFontWeight = 700 if self.excelCellObject.Font.Bold else 400
#Fetching Font Name and style information
sFontName = self.excelCellObject.Font.Name
sFontItalic = self.excelCellObject.Font.Italic
sFontUnderline = True if self.excelCellObject.Font.Underline else False
sFontStrikeThrough = self.excelCellObject.Font.Strikethrough
#If FontSize is <0: The font mapper transforms this value into device units
#and matches its absolute value against the character height of the available fonts.
iFontHeight = iFontSize * -1
#If Font Width is 0, the font mapper chooses a closest match value.
iFontWidth = 0
iEscapement = 0
iOrientation = 0
#Default CharSet based on System Locale is chosen
iCharSet = 0
#Default font mapper behavior
iOutputPrecision = 0
#Default clipping behavior
iClipPrecision = 0
#Default Quality
iOutputQuality = 0
#Default Pitch and default font family
iPitchAndFamily = 0
#Create a font object with the correct size, weight and style
hFont = ctypes.windll.gdi32.CreateFontW(iFontHeight, iFontWidth, iEscapement, iOrientation, iFontWeight, sFontItalic, sFontUnderline, sFontStrikeThrough, iCharSet, iOutputPrecision, iClipPrecision, iOutputQuality, iPitchAndFamily, sFontName)
#Load the font into the device context, storing the original font object
hOldFont = ctypes.windll.gdi32.SelectObject(tempDC, hFont)
sText = self.excelCellObject.Text
textLength = len(sText)
class structText(ctypes.Structure):
_fields_ = [("width", ctypes.c_int), ("height",ctypes.c_int)]
StructText = structText()
getTextExtentPoint = ctypes.windll.gdi32.GetTextExtentPoint32W
getTextExtentPoint.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_int, ctypes.POINTER(structText)]
getTextExtentPoint.restype = ctypes.c_int
sText = unicode(sText)
#Get the text dimensions
ctypes.windll.gdi32.GetTextExtentPoint32W(tempDC, sText, textLength,ctypes.byref(StructText))
#Restore the old Font Object
ctypes.windll.gdi32.SelectObject(tempDC, hOldFont)
#Delete the font object we created
ctypes.windll.gdi32.DeleteObject(hFont)
#Restore the old Bitmap Object
ctypes.windll.gdi32.SelectObject(tempDC, hOldBMP)
#Delete the temporary BitMap Object
ctypes.windll.gdi32.DeleteObject(hBMP)
#Release & Delete the device context
ctypes.windll.gdi32.DeleteDC(tempDC)
#Retrieve the text width
textWidth = StructText.width+5
cellWidth = self.excelCellObject.ColumnWidth * xlCellWidthUnitToPixels #Conversion factor to convert the cellwidth to pixels
return (cellWidth,textWidth)
def _get__overlapInfo(self):
(cellWidth, textWidth) = self.getCellWidthAndTextWidth()
isWrapText = self.excelCellObject.WrapText
isShrinkToFit = self.excelCellObject.ShrinkToFit
isMerged = self.excelWindowObject.Selection.MergeCells
adjacentCell = self.excelCellObject.Offset(0,1)
if adjacentCell.Text:
isAdjacentCellEmpty = False
else:
isAdjacentCellEmpty = True
info = {}
if isMerged:
columnCountInMergeArea = self.excelCellObject.MergeArea.Columns.Count
curCol = self.excelCellObject.Column
curRow = self.excelCellObject.Row
cellWidth = 0
for x in xrange(columnCountInMergeArea):
cellWidth += self.excelCellObject.Cells(curRow, curCol).ColumnWidth
curCol += 1
cellWidth = cellWidth * xlCellWidthUnitToPixels #Conversion factor to convert the cellwidth to pixels
if isWrapText or isShrinkToFit or textWidth <= cellWidth:
info = None
else:
if isAdjacentCellEmpty:
info['obscuringRightBy']= textWidth - cellWidth
info['obscuredFromRightBy'] = 0
else:
info['obscuredFromRightBy']= textWidth - cellWidth
info['obscuringRightBy'] = 0
self._overlapInfo = info
return self._overlapInfo
def _get_parent(self):
worksheet=self.excelCellObject.Worksheet
self.parent=ExcelWorksheet(windowHandle=self.windowHandle,excelWindowObject=self.excelWindowObject,excelWorksheetObject=worksheet)
@@ -187,6 +187,8 @@
STATE_HASFORMULA=0x1000000000 #Mostly for spreadsheets
STATE_HASCOMMENT=0X2000000000
STATE_OBSCURED=0x4000000000
STATE_CROPPED=0x8000000000
STATE_OVERFLOWING=0x10000000000
roleLabels={
# Translators: The word for an unknown control type.
@@ -549,6 +551,10 @@
STATE_HASCOMMENT:_("has comment"),
# Translators: a state that denotes that the object is covered partially or fully by another object
STATE_OBSCURED:_("obscured"),
# Translators: a state that denotes that the object(text) is cropped as it couldn't be accommodated in the allocated/available space
STATE_CROPPED:_("cropped"),
# Translators: a state that denotes that the object(text) is overflowing into the adjacent space
STATE_OVERFLOWING:_("overflowing"),
}
negativeStateLabels={
@@ -8,6 +8,7 @@
== New Features ==
- moving forward and backward by sentence in Microsoft Word is now possible with alt+downArrow and alt+upArrow respectively. (#3288)
- New braille translation tables for several Indian languages. (#4778)
- In Microsoft Excel, NVDA now reports when a cell has overflowing or cropped content. (#3040)
== Changes ==

0 comments on commit 785fc4e

Please sign in to comment.