Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve working with message lists and calendars in Outlook #7949

Merged
merged 17 commits into from Apr 30, 2018

Conversation

LeonarddeR
Copy link
Collaborator

@LeonarddeR LeonarddeR commented Jan 31, 2018

Link to issue number:

Fixes #6911
Fixes #8028
Reverts #6219

Summary of the issue:

  1. In the Outlook messages list, replied to or forwarded status is not announced by NVDA.
  2. In outlook's calendar view, the month view is overly verbose, announcing redundant information (e.g. 00.00AM to next day 00.00AM
  3. When a message has an associated draft, this is not reported.

Description of how this pull request fixes the issue:

  1. This pr gets the announcement of replied/forwarded state from the UIA value of rows in the Outlook messages list. NVDA will now also announce meeting requests based on this information, as well as appointment cancellations.

    The initial implementation of this pr relied on the Outlook object model. However, this caused security warnings on some systems with a tight security policy.

  2. When an appointment or time slot is now exactly one day (86400 seconds), and starts at 00.00, the time slot is announced as 26 february 2018 (entire day) instead of 26 februari 2018 00.00 to 27 februari 2018 00.00. While looking at this code, I noticed that Microsoft strongly discourages the use of kernel32 GetTimeFormat and GetDateFormat functions, so I changed this implementation to use the *Ex alternatives for these functions.

  3. The associated draft column in Outlook 2016 is no longer silenced. After implementing Outlook 2016: NVDA reads "Associated draft, no associated drafts" for every message #6219, it seems Microsoft decided to present an empty text node when there is no associated draft, rather than spamming everyone with the "no associated draft" message. Therefore when this particular pr is merged, everyone who gets "no associated draft" for almost every message is advised to update Outlook 2016 to the most recent build.

Testing performed:

  1. Made sure that the current implementation doesn't cause security warnings when setting outlook's program access settings to the most secure option available.
  2. Tested replied/forwarded messages in Outlook 2016 and 2013, the state was reported correctly. The replied state did even report for messages I replied to using Thunderbird. Also tested this in Outlook 2010, and as Outlook 2010 doesn't expose this information using UIA, we fall back to the object model for the unread state.
  3. Tested the announcement of a whole day appointment in the calendar

Known issues with pull request:

  1. The replied or forwarded state is localized by Outlook itself, not by NVDA. This shouldn't be a problem though, as the headers are also localized by Outlook itself.

  2. In theory, Outlook could expose every piece of relevant or irrelevant information using the UIA value. I've only seen the following strings until now:

    • Message: usually the first word in the value of a message
    • Contact: usually the first word in the value of a contact when the contacts are displayed in a list view
    • Appointment: usually the first word in the value of a calendar item when the calendar is displayed in a list view
    • Read/Unread: usually the last word in the value of a message, contact or appointment
    • Forwarded/Replied: usually the second word in a string containing three words, e.g. Message Replied Read

    I'm quite sure JAWS also relies on the value here, as replied/forwarded state is localized using Outlook, not using JAWS. The wild should make clear whether parsing the value this way is too non-restrictive.

  3. The replied to all state is not reported as it is not exposed using the object's value.

  4. When the root of a conversation in conversation view has focus, NVDA reads the headers of every single message in the conversation. There is currently no suitable workaround for this. Note that this was already the case before this pr. This issue is caused by a bug in UIA, where the tree scope is ignored when providing a custom tree filter for a cache request.

Change log entry:

michaelDCurran
michaelDCurran previously approved these changes Jan 31, 2018
@LeonarddeR
Copy link
Collaborator Author

Blocked by #7953

@LeonarddeR LeonarddeR dismissed michaelDCurran’s stale review February 3, 2018 12:11

Implementation had to be changed completely.

@LeonarddeR
Copy link
Collaborator Author

I had to change this into a completely different implementation due to #7953. @michaelDCurran. It would be great if you could review this as soon as possible to fix #7953.

@LeonarddeR LeonarddeR removed the blocked label Feb 3, 2018
# The first valuePart is the type of the selection, e.g. Message, Contact.
# The last valuePart indicates whether the message is read or unread.
if len(valueParts)>=3:
textList.extend(valueParts[1:-1])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we be sure that the first part (message, contact etc) is never more than one word in all languages?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, which also applies to read/unread I belief.

Though JAWS uses these translated strings, I"m pretty sure they do some string matching on it, as the read state is ignored when Both Outlook and JAWS are set to Dutch, but the state is preserved when Outlook is Dutch and JAWS is English. So that's definitely not a clean solution.

I belief both Message and Unread are part of the NVDA translation, so it should be doable to check whether these words contain spaces in other languages without intervention of every single translator.

@LeonarddeR LeonarddeR changed the title Show replied/forwarded status for messages in Outlook Improve working with message lists and calendars in Outlook Feb 26, 2018
@LeonarddeR
Copy link
Collaborator Author

@michaelDCurran: I made the scope of this pr somewhat broader and also addressed some other concerns there were with the current way of dealing with Outlook. The initial message of the pr covers all relevant information.

}
#: When in a list view, the message classes which should not be announced for an item.
#: For these, it should be safe to assume that their names consist of only one word.
silentMessageClasses = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is no such class for a message/email?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the note one. I added a comment that clarifies this.

CalendarView._lastStartDate=startDate
if endDate!=startDate:
if (endDate - startDate).total_seconds()==SECONDS_PER_DAY:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also catches events that start at noon on one day and end at noon on the next. Do we want to call these all day events or should we check for the start and end times being midnight as well?

CalendarView._lastStartDate=startDate
if endDate!=startDate:
if (endDate - startDate).total_seconds()==SECONDS_PER_DAY:
# Translators: a message reporting the date of a whole day Outlook calendar entry
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outlook calls them "All day event", not "whole day".

if endDate!=startDate:
if (endDate - startDate).total_seconds()==SECONDS_PER_DAY:
# Translators: a message reporting the date of a whole day Outlook calendar entry
return _("{date} (entire day)").format(date=startDateText)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, "all day" may be better here.

# Do not expose the read state
lastPart = valueCount if unread else valueCount-1
# The first valuePart is the type of the selection, e.g. Message, Contact, meeting request.
# We can safely assume that the message class of a regular message or appointment is one word.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet the example you give above is "Meeting request". Is this not regular? If so, 2 words should be filtered out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to improve the clarity of the comments. Meeting request is regular, but it isn't part of silentMessageClasses and therefore always announced.

# Thus we filter it out.
if self.appModule.outlookVersion>=16 and e.cachedClassName=="DraftFlagField":
continue
isFlag = e.cachedClassName=="FlagField"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this handle the "DraftFlagField" case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I forgot to mention this in the initial pr description, I surely should have done that. It is still open to discussion.

MS no longer exposes "no associated draft" as a text node by default. Instead, the text node is empty. Furthermore, the "no associated draft" patch meant that it would be never announced when a message has an associated draft. Therefore, I propose people who have the "no associated draft" issue updating their outlook to fix this, rather than keeping the old patch. CC @bramd

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur.

@derekriemer
Copy link
Collaborator

what about saying "all day" instead of "entire day"

@LeonarddeR
Copy link
Collaborator Author

@derekriemer commented on 5 mrt. 2018 15:53 CET:

what about saying "all day" instead of "entire day"

It is now saying "all day" as per the last commits from today morning.

@LeonarddeR
Copy link
Collaborator Author

@michaelDCurran, this pr has been overhauled and is ready for another review I think. I'm afraid there's no way to work around relying on the localized contents of the UIA value.

@LeonarddeR
Copy link
Collaborator Author

@josephsl commented on 15 mrt. 2018 06:18 CET:

I wonder if this is the right PR for this.

Looks like it is. It turns out it wasn't a good idea to remove the tree filter from the cache request that forced the fetched children to be text controls. I now added a new tree filter that requires the children to be content children. After that, I couldn't reproduce the issue any more.

I also noticed another bug in the code that tried to access the object model for flag information when there was no selection. That bug was actually obfuscated by the treeFilter one. We are now ignoring flags when there is no object model access, just as we did before this pr.

@LeonarddeR
Copy link
Collaborator Author

Currently blocked by #8129. When getting the name for message list items, a NULL COM pointer access error is raised because the custom UIA query fails. This is a bit strange, since until now, it fails only on two systems. @bramd has a system where it fails and another system where it works correctly, same windows and office builds.

Note that such an error has been reported by @josephsl in #7949 (comment), the fix for that has yet not been committed to Next. However, testing by @bramd tells that the fix for #7949 (comment) does not aplly to this particular case of the null com pointer access error.

I guess we can do an if check on cachedChildren, but I'd like to no why getting cached children would reveal a null com pointer in the first place. @michaelDCurran: Have you seen these cases earlier?

@michaelDCurran
Copy link
Member

michaelDCurran commented Mar 28, 2018 via email

michaelDCurran added a commit that referenced this pull request Mar 28, 2018
…e the ContentViewCondition as tree filter instead of creating a property condition for content elements.
@LeonarddeR
Copy link
Collaborator Author

I reverted the announcement of importance, attachments and flags based on UIA children, as it is unreliable in conversation view. The announcement of these fields was based on the assumption that the UIA implementation treats relevant fields as content (i.e. with the IsContentElement property) whereas irrelevant fields (no attachment, no reminder) are non content. However, when conversation view is enabled, none of the relevant children have the IsContentElement property set.

… mixed with tree view items (e.g. in conversation view)
@LeonarddeR
Copy link
Collaborator Author

@michaelDCurran: Could you please review the last few commits?

michaelDCurran added a commit that referenced this pull request Apr 15, 2018
@michaelDCurran michaelDCurran merged commit 758a116 into nvaccess:master Apr 30, 2018
@nvaccessAuto nvaccessAuto added this to the 2018.2 milestone Apr 30, 2018
@LeonarddeR LeonarddeR added the BabbageWork Pull requests filed on behalf of Babbage B.V. label Oct 11, 2019
@seanbudd seanbudd mentioned this pull request Mar 5, 2021
18 tasks
@seanbudd seanbudd added the deprecated/2021.1 Label used to track deprecations due for removal in the 2021.1 release label Mar 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
app/microsoft-office BabbageWork Pull requests filed on behalf of Babbage B.V. deprecated/2021.1 Label used to track deprecations due for removal in the 2021.1 release quick fix
Projects
None yet
7 participants