From 4a0cee06ff19b9f2fd5d7e7e84be1b05825418f0 Mon Sep 17 00:00:00 2001 From: Takuya Nishimoto Date: Fri, 21 Oct 2016 19:53:40 +0900 Subject: [PATCH 1/3] Information about the cell border is given in an Excel sheet, if the cell border is different from the adjacent cells. #3044 --- source/NVDAObjects/window/excel.py | 9 ++ source/NVDAObjects/window/excelCellBorder.py | 159 +++++++++++++++++++ source/config/__init__.py | 2 + source/gui/settingsDialogs.py | 27 +++- source/speech.py | 10 ++ user_docs/en/userGuide.t2t | 1 + 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 source/NVDAObjects/window/excelCellBorder.py diff --git a/source/NVDAObjects/window/excel.py b/source/NVDAObjects/window/excel.py index a3794c102b1..4e044dcdfce 100755 --- a/source/NVDAObjects/window/excel.py +++ b/source/NVDAObjects/window/excel.py @@ -196,6 +196,8 @@ xlPatternRectangularGradient:_("rectangular gradient"), } +from excelCellBorder import getCellBorderStyleDescription + re_RC=re.compile(r'R(?:\[(\d+)\])?C(?:\[(\d+)\])?') re_absRC=re.compile(r'^R(\d+)C(\d+)(?::R(\d+)C(\d+))?$') @@ -958,6 +960,13 @@ def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True): formatField['background-color']=colors.RGB.fromCOLORREF(int(cellObj.interior.color)) except COMError: pass + if formatConfig["reportBorderStyle"]: + if self.obj.excelCellObject.mergeCells: + cellObj=self.obj.excelCellObject.mergeArea.DisplayFormat + try: + formatField['border-style']=getCellBorderStyleDescription(cellObj.borders,reportBorderColor=formatConfig['reportBorderColor']) + except COMError: + pass return formatField,(self._startOffset,self._endOffset) class ExcelCell(ExcelBase): diff --git a/source/NVDAObjects/window/excelCellBorder.py b/source/NVDAObjects/window/excelCellBorder.py new file mode 100644 index 00000000000..4765e8b24ec --- /dev/null +++ b/source/NVDAObjects/window/excelCellBorder.py @@ -0,0 +1,159 @@ +#NVDAObjects/window/excelCellBorder.py +#A part of NonVisual Desktop Access (NVDA) +#Copyright (C) 2016 Takuya Nishimoto +#This file is covered by the GNU General Public License. +#See the file COPYING for more details. + +from collections import OrderedDict +import colors +# XlBordersIndex Enumeration +# see https://msdn.microsoft.com/en-us/library/office/ff835915.aspx +xlDiagonalDown = 5 +xlDiagonalUp = 6 +xlEdgeBottom = 9 +xlEdgeLeft = 7 +xlEdgeRight = 10 +xlEdgeTop = 8 +xlInsideHorizontal = 12 +xlInsideVertical = 11 +bordersIndexLabels=OrderedDict(( + # Translators: border positions in Microsoft Excel. + (xlEdgeTop, _("top edge")), + # Translators: border positions in Microsoft Excel. + (xlEdgeBottom, _("bottom edge")), + # Translators: border positions in Microsoft Excel. + (xlEdgeLeft, _("left edge")), + # Translators: border positions in Microsoft Excel. + (xlEdgeRight, _("right edge")), + # Translators: border positions in Microsoft Excel. + (xlDiagonalUp, _("up-right diagonal line")), + # Translators: border positions in Microsoft Excel. + (xlDiagonalDown, _("down-right diagonal line")), + # Translators: border positions in Microsoft Excel. + (xlInsideHorizontal, _("horizontal borders except outside")), + # Translators: border positions in Microsoft Excel. + (xlInsideVertical, _("vertical borders except outside")), +)) +# XlLineStyle Enumeration +# see https://msdn.microsoft.com/en-us/library/office/ff821622.aspx +xlContinuous = 1 +xlDash = -4115 +xlDashDot = 4 +xlDashDotDot = 5 +xlDot = -4118 +xlDouble = -4119 +xlLineStyleNone = -4142 +xlSlantDashDot = 13 +borderStyleLabels={ + # Translators: border styles in Microsoft Excel. + xlContinuous:_("continuous"), + # Translators: border styles in Microsoft Excel. + xlDash:_("dashed"), + # Translators: border styles in Microsoft Excel. + xlDashDot:_("dash dot"), + # Translators: border styles in Microsoft Excel. + xlDashDotDot:_("dash dot dot"), + # Translators: border styles in Microsoft Excel. + xlDot:_("dotted"), + # Translators: border styles in Microsoft Excel. + xlDouble:_("double"), + # Translators: border styles in Microsoft Excel. + xlSlantDashDot:_("slanted dash dot"), +} +# XlBorderWeight Enumeration +# see https://msdn.microsoft.com/en-us/library/office/ff197515.aspx +xlHairline = 1 # thinnest border +xlThin = 2 +xlMedium = -4138 +xlThick = 4 # widest border +borderWeightLabels={ + # Translators: border styles in Microsoft Excel. + xlHairline:_("hair"), + # Translators: border styles in Microsoft Excel. + xlThin:_("thin"), + # Translators: border styles in Microsoft Excel. + xlMedium:_("medium"), + # Translators: border styles in Microsoft Excel. + xlThick:_("thick"), +} +borderStyleAndWeightLabels={ + # Translators: border styles in Microsoft Excel. + (xlContinuous, xlHairline):_("hair"), + # Translators: border styles in Microsoft Excel. + (xlDot, xlThin):_("dotted"), + # Translators: border styles in Microsoft Excel. + (xlDashDotDot, xlThin):_("dash dot dot"), + # Translators: border styles in Microsoft Excel. + (xlDashDot, xlThin):_("dash dot"), + # Translators: border styles in Microsoft Excel. + (xlDash, xlThin):_("dashed"), + # Translators: border styles in Microsoft Excel. + (xlContinuous, xlThin):_("thin"), + # Translators: border styles in Microsoft Excel. + (xlDashDotDot, xlMedium):_("medium dash dot dot"), + # Translators: border styles in Microsoft Excel. + (xlSlantDashDot, xlMedium):_("slanted dash dot"), + # Translators: border styles in Microsoft Excel. + (xlDashDot, xlMedium):_("medium dash dot"), + # Translators: border styles in Microsoft Excel. + (xlDash, xlMedium):_("medium dashed"), + # Translators: border styles in Microsoft Excel. + (xlContinuous, xlMedium):_("medium"), + # Translators: border styles in Microsoft Excel. + (xlContinuous, xlThick):_("thick"), + # Translators: border styles in Microsoft Excel. + (xlDouble, xlThick):_("double"), +} + +def getCellBorderStyleDescription(bordersObj,reportBorderColor=False): + d=OrderedDict() + for pos in bordersIndexLabels.keys(): + border=bordersObj[pos] + if border.lineStyle != xlLineStyleNone: + style=border.lineStyle + weight=border.weight + desc=borderStyleAndWeightLabels.get((style,weight)) + if not desc: + # Translators: border styles in Microsoft Excel. + desc=_("{weight} {style}").format( + style=borderStyleLabels.get(style), + weight=borderWeightLabels.get(weight) + ) + if reportBorderColor: + # Translators: border styles in Microsoft Excel. + d[pos]=_("{color} {desc}").format( + color=colors.RGB.fromCOLORREF(int(border.color)).name, + desc=desc + ) + else: + d[pos]=desc + s=[] + if d.get(xlEdgeTop) == d.get(xlEdgeBottom) == d.get(xlEdgeLeft) == d.get(xlEdgeRight) and d.get(xlEdgeTop) is not None: + # Translators: border styles in Microsoft Excel. + s.append(_("{desc} surrounding border").format(desc=d.get(xlEdgeTop))) + del d[xlEdgeTop] + del d[xlEdgeBottom] + del d[xlEdgeLeft] + del d[xlEdgeRight] + if d.get(xlEdgeTop) == d.get(xlEdgeBottom) and d.get(xlEdgeTop) is not None: + # Translators: border styles in Microsoft Excel. + s.append(_("{desc} top and bottom edges").format(desc=d.get(xlEdgeTop))) + del d[xlEdgeTop] + del d[xlEdgeBottom] + if d.get(xlEdgeLeft) == d.get(xlEdgeRight) and d.get(xlEdgeLeft) is not None: + # Translators: border styles in Microsoft Excel. + s.append(_("{desc} left and right edges").format(desc=d.get(xlEdgeLeft))) + del d[xlEdgeLeft] + del d[xlEdgeRight] + if d.get(xlDiagonalUp) == d.get(xlDiagonalDown) and d.get(xlDiagonalUp) is not None: + # Translators: border styles in Microsoft Excel. + s.append(_("{desc} up-right and down-right diagonal lines").format(desc=d.get(xlDiagonalUp))) + del d[xlDiagonalUp] + del d[xlDiagonalDown] + for pos,desc in d.items(): + # Translators: border styles in Microsoft Excel. + s.append(_("{desc} {position}").format( + desc=desc, + position=bordersIndexLabels.get(pos) + )) + return ', '.join(s) diff --git a/source/config/__init__.py b/source/config/__init__.py index d7cf7bd324d..a7dd4c616f9 100644 --- a/source/config/__init__.py +++ b/source/config/__init__.py @@ -194,6 +194,8 @@ def validateConfig(configObj,validator,validationResult=None,keyList=None): includeLayoutTables = boolean(default=False) reportTableHeaders = boolean(default=True) reportTableCellCoords = boolean(default=True) + reportBorderStyle = boolean(default=True) + reportBorderColor = boolean(default=True) reportLinks = boolean(default=true) reportComments = boolean(default=true) reportLists = boolean(default=true) diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 87fc44702c6..209aca24b65 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -1212,6 +1212,28 @@ def makeSettings(self, settingsSizer): self.tableCellCoordsCheckBox=tablesGroup.addItem(wx.CheckBox(scrolledPanel,label=_("Cell c&oordinates"))) self.tableCellCoordsCheckBox.SetValue(config.conf["documentFormatting"]["reportTableCellCoords"]) + borderChoices=[ + # Translators: This is the label for a combobox in the + # document formatting settings dialog. + _("Off"), + # Translators: This is the label for a combobox in the + # document formatting settings dialog. + _("Styles"), + # Translators: This is the label for a combobox in the + # document formatting settings dialog. + _("Both Colors and Styles"), + ] + # Translators: This is the label for a combobox in the + # document formatting settings dialog. + self.borderComboBox=tablesGroup.addLabeledControl(_("Cell borders:"), wx.Choice, choices=borderChoices) + curChoice = 0 + if config.conf["documentFormatting"]["reportBorderStyle"]: + if config.conf["documentFormatting"]["reportBorderColor"]: + curChoice = 2 + else: + curChoice = 1 + self.borderComboBox.SetSelection(curChoice) + # Translators: This is the label for a group of document formatting options in the # document formatting settings dialog elementsGroupText = _("Elements") @@ -1289,7 +1311,10 @@ def onOk(self,evt): config.conf["documentFormatting"]["reportLineSpacing"]=self.lineSpacingCheckBox.IsChecked() config.conf["documentFormatting"]["reportTables"]=self.tablesCheckBox.IsChecked() config.conf["documentFormatting"]["reportTableHeaders"]=self.tableHeadersCheckBox.IsChecked() - config.conf["documentFormatting"]["reportTableCellCoords"]=self.tableCellCoordsCheckBox.IsChecked() + config.conf["documentFormatting"]["reportTableCellCoords"]=self.tableCellCoordsCheckBox.IsChecked() + choice = self.borderComboBox.GetSelection() + config.conf["documentFormatting"]["reportBorderStyle"] = choice in (1,2) + config.conf["documentFormatting"]["reportBorderColor"] = (choice == 2) config.conf["documentFormatting"]["reportLinks"]=self.linksCheckBox.IsChecked() config.conf["documentFormatting"]["reportHeadings"]=self.headingsCheckBox.IsChecked() config.conf["documentFormatting"]["reportLists"]=self.listsCheckBox.IsChecked() diff --git a/source/speech.py b/source/speech.py index c213b05bb50..79c92d56795 100755 --- a/source/speech.py +++ b/source/speech.py @@ -1160,6 +1160,16 @@ def getFormatFieldSpeech(attrs,attrsCache=None,formatConfig=None,unit=None,extra # A style is a collection of formatting settings and depends on the application. text=_("default style") textList.append(text) + if formatConfig["reportBorderStyle"]: + borderStyle=attrs.get("border-style") + oldBorderStyle=attrsCache.get("border-style") if attrsCache is not None else None + if borderStyle!=oldBorderStyle: + if borderStyle: + text=borderStyle + else: + # Translators: Indicates that cell does not have border lines. + text=_("no border lines") + textList.append(text) if formatConfig["reportFontName"]: fontFamily=attrs.get("font-family") oldFontFamily=attrsCache.get("font-family") if attrsCache is not None else None diff --git a/user_docs/en/userGuide.t2t b/user_docs/en/userGuide.t2t index 4c713fa8c2d..975d03af21c 100644 --- a/user_docs/en/userGuide.t2t +++ b/user_docs/en/userGuide.t2t @@ -1219,6 +1219,7 @@ You can configure reporting of: - Tables - Row/column headers - Cell coordinates + - Cell borders [(Off, Styles, Both Colors and Styles) - Elements - Headings - Links From 87cfe8bd8144292126ebc63b4df0ecc7ae51477f Mon Sep 17 00:00:00 2001 From: Takuya Nishimoto Date: Thu, 19 Jan 2017 13:56:54 +0900 Subject: [PATCH 2/3] Information about the cell border is given in an Excel sheet, if the cell border is different from the adjacent cells. NVDA+F should work on Excel as well. #3044 PR #6492 --- source/globalCommands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/globalCommands.py b/source/globalCommands.py index d400863d6cd..58885cbf973 100755 --- a/source/globalCommands.py +++ b/source/globalCommands.py @@ -1271,6 +1271,7 @@ def script_reportFormatting(self,gesture): "reportPage":False,"reportLineNumber":False,"reportLineIndentation":True,"reportLineIndentationWithTones":False,"reportParagraphIndentation":True,"reportLineSpacing":True,"reportTables":False, "reportLinks":False,"reportHeadings":False,"reportLists":False, "reportBlockQuotes":False,"reportComments":False, + "reportBorderStyle":True,"reportBorderColor":True, } textList=[] info=api.getReviewPosition() From 46a5676ba361f27a68187e4c40268faf2ef52ba6 Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Fri, 17 Feb 2017 19:20:06 +0100 Subject: [PATCH 3/3] get cell borders in excel 2007 Fixes #6889 The `DisplayFormat` property does not exist on ranges for excel 2007. Instead (if the call to DisplayFormat fails) the borders property is accessed directly on the range object rather than through the `DisplayFormat` --- source/NVDAObjects/window/excel.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/NVDAObjects/window/excel.py b/source/NVDAObjects/window/excel.py index 89e40245cf8..ddb10a587e1 100755 --- a/source/NVDAObjects/window/excel.py +++ b/source/NVDAObjects/window/excel.py @@ -988,10 +988,18 @@ def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True): except COMError: pass if formatConfig["reportBorderStyle"]: - if self.obj.excelCellObject.mergeCells: - cellObj=self.obj.excelCellObject.mergeArea.DisplayFormat + borders = None + hasMergedCells = self.obj.excelCellObject.mergeCells + if hasMergedCells: + mergeArea = self.obj.excelCellObject.mergeArea + try: + borders = mergeArea.DisplayFormat.borders # for later versions of office + except COMError: + borders = mergeArea.borders # for office 2007 + else: + borders = cellObj.borders try: - formatField['border-style']=getCellBorderStyleDescription(cellObj.borders,reportBorderColor=formatConfig['reportBorderColor']) + formatField['border-style']=getCellBorderStyleDescription(borders,reportBorderColor=formatConfig['reportBorderColor']) except COMError: pass return formatField,(self._startOffset,self._endOffset)