Repository: nvaccess/nvda

Issue:
"Categories" not reported for messages in Outlook
Outlook has a "Categories" feature which can be used to mark messages into well, categories.  By default, the category names are colours - red, green. blue etc, but the first time you assign one, you are invited to rename it if you want.  

To mark a message, select it then press the applications key to open the context menu, choose "Categorize" (T), then pick one from the list.

When you navigate through the Inbox, categorized messages have a coloured square as an indicator, however, NVDA does not report anything to indicate that a message has a category.

If you open a message, you can press SHIFT+TAB to move back to the header information and the category is reported there ("Red category", "In-Progress", whatever other names you've given categories, etc).

Expected behaviour would be that NVDA reports any categories (a message can have multiple categories) along with other information when navigating through it in a mail folder.

Using the current version of Outlook 2016 / 365: 1807 build 10325.20082 Click to run, on the latest Windows fast insider 1803, build 17730.1000 and NVDA Version: alpha-15781,d58e1cd4

The behaviour is the same when using NVDA 2018.2.1.

NVDA DOES report "Red flag" when messages are flagged for follow up (that is a different feature of Outlook).

Narrator DOES report categories when navigating.


Discussion:

Resolving patch:
diff --git a/source/appModules/outlook.py b/source/appModules/outlook.py
--- a/source/appModules/outlook.py
+++ b/source/appModules/outlook.py
@@ -17,6 +17,7 @@
 import appModuleHandler
 import eventHandler
 import UIAHandler
+from UIAUtils import createUIAMultiPropertyCondition
 import api
 import controlTypes
 import config
@@ -33,27 +34,6 @@
 #: Type: float
 SECONDS_PER_DAY = 86400.0
 
-oleFlagIconLabels={
-	# Translators: a flag for a Microsoft Outlook message
-	# See https://msdn.microsoft.com/en-us/library/office/aa211991(v=office.11).aspx
-	1:_("purple flag"),
-	# Translators: a flag for a Microsoft Outlook message
-	# See https://msdn.microsoft.com/en-us/library/office/aa211991(v=office.11).aspx
-	2:_("Orange flag"),
-	# Translators: a flag for a Microsoft Outlook message
-	# See https://msdn.microsoft.com/en-us/library/office/aa211991(v=office.11).aspx
-	3:_("Green flag"),
-	# Translators: a flag for a Microsoft Outlook message
-	# See https://msdn.microsoft.com/en-us/library/office/aa211991(v=office.11).aspx
-	4:_("Yellow flag"),
-	# Translators: a flag for a Microsoft Outlook message
-	# See https://msdn.microsoft.com/en-us/library/office/aa211991(v=office.11).aspx
-	5:_("Blue flag"),
-	# Translators: a flag for a Microsoft Outlook message
-	# See https://msdn.microsoft.com/en-us/library/office/aa211991(v=office.11).aspx
-	6:_("Red flag"),
-}
-
 importanceLabels={
 	# Translators: for a high importance email
 	2:_("high importance"),
@@ -439,12 +419,6 @@ def _get_name(self):
 				unread=False
 			# Translators: when an email is unread
 			if unread: textList.append(_("unread"))
-			try:
-				flagIcon=selection.flagIcon
-			except COMError:
-				flagIcon=0
-			flagIconLabel=oleFlagIconLabels.get(flagIcon)
-			if flagIconLabel: textList.append(flagIconLabel)
 			try:
 				attachmentCount=selection.attachments.count
 			except COMError:
@@ -468,7 +442,8 @@ def _get_name(self):
 		childrenCacheRequest.addProperty(UIAHandler.UIA_NamePropertyId)
 		childrenCacheRequest.addProperty(UIAHandler.UIA_TableItemColumnHeaderItemsPropertyId)
 		childrenCacheRequest.TreeScope=UIAHandler.TreeScope_Children
-		childrenCacheRequest.treeFilter=UIAHandler.handler.clientObject.createPropertyCondition(UIAHandler.UIA_ControlTypePropertyId,UIAHandler.UIA_TextControlTypeId)
+		# We must filter the children for just text and image elements otherwise getCachedChildren fails completely in conversation view.
+		childrenCacheRequest.treeFilter=createUIAMultiPropertyCondition({UIAHandler.UIA_ControlTypePropertyId:[UIAHandler.UIA_TextControlTypeId,UIAHandler.UIA_ImageControlTypeId]})
 		cachedChildren=self.UIAElement.buildUpdatedCache(childrenCacheRequest).getCachedChildren()
 		if not cachedChildren:
 			# There are no children
@@ -477,6 +452,26 @@ def _get_name(self):
 			return super(UIAGridRow, self).name
 		for index in xrange(cachedChildren.length):
 			e=cachedChildren.getElement(index)
+			UIAControlType=e.cachedControlType
+			UIAClassName=e.cachedClassName
+			# We only want to include particular children.
+			# We only include the flagField if the object model's flagIcon or flagStatus is set.
+			# Stops us from reporting "unflagged" which is too verbose.
+			if selection and UIAClassName=="FlagField":
+				try:
+					if not selection.flagIcon and not selection.flagStatus: continue
+				except COMError:
+					continue
+			# the category field should only be reported if the objectModel's categories property actually contains a valid string.
+			# Stops us from reporting "no categories" which is too verbose.
+			elif selection and UIAClassName=="CategoryField":
+				try:
+					if not selection.categories: continue
+				except COMError:
+					continue
+			# And we don't care about anything else that is not a text element. 
+			elif UIAControlType!=UIAHandler.UIA_TextControlTypeId:
+				continue
 			name=e.cachedName
 			columnHeaderTextList=[]
 			if name and config.conf['documentFormatting']['reportTableHeaders']:
@@ -494,8 +489,11 @@ def _get_name(self):
 			else:
 				text=name
 			if text:
-				text+=u","
-				textList.append(text)
+				if UIAClassName=="FlagField":
+					textList.insert(0,text)
+				else:
+					text+=u","
+					textList.append(text)
 		return " ".join(textList)
 
 	value=None


Test patch: