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

Implementing HeadingLevel and IsDialog automation properties #4751

Merged
merged 44 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b98bb57
Felipe coworking session for new UIAutomation property investigation
ryalanms May 25, 2021
9a5eb0e
adding None as the default result
May 26, 2021
0174765
adding apicompat changes
May 26, 2021
1a5afaf
Coworking session with Felipe: adding OS checks for new automation pr…
ryalanms Jun 9, 2021
adc3050
Merge branch 'main' into new.automation.property
ryalanms Jun 9, 2021
0cf1bdc
Merge branch 'main' into new.automation.property
ryalanms Jun 16, 2021
03125c0
Fix reference assemblies
ryalanms Jun 16, 2021
edd1008
Changing HeadingLevel enum to be in the correct way
Jun 22, 2021
0bcb251
adding isdialog implementation
Jul 5, 2021
0e3ff1d
changing to isdialog from getisdialog
Jul 5, 2021
3a8be23
improving isdialog implementation
Jul 6, 2021
ac060ac
Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/A…
guimafelipe Jul 6, 2021
e49e2b0
Update src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClient/S…
guimafelipe Jul 6, 2021
7393512
Update src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationTypes/Sy…
guimafelipe Jul 6, 2021
81a1df3
Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/A…
guimafelipe Jul 6, 2021
1ee85b4
Update src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationTypes/Sy…
guimafelipe Jul 6, 2021
cbbc720
Update src/Microsoft.DotNet.Wpf/src/Shared/System/Windows/InterOp/OSV…
guimafelipe Jul 6, 2021
3921923
adding headinglevel summary
Jul 6, 2021
ba44bdd
removing empty lines and adding description
Jul 6, 2021
118a26a
Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/A…
guimafelipe Jul 6, 2021
f092113
Update src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/A…
guimafelipe Jul 6, 2021
d223aa8
suggested changes
Jul 6, 2021
df19535
removing unecessary comment and adding rs5 for isDialog
Jul 6, 2021
df85bbd
changing enum constant
Jul 7, 2021
d01beaa
Adding window isdialogcore implementation
Jul 7, 2021
a3ee3c1
overriding headinglevelcore in peers
Jul 7, 2021
3944e81
editing override of isdialog
Jul 7, 2021
a2ad746
changing values of enum for heading level so it correctly show in acc…
Jul 8, 2021
fed5d29
changing IsDialogCore() to virtual
Jul 9, 2021
23cc6b6
adding prefix in automation properties
Jul 9, 2021
0afb956
changing location of automationheadinglevel.cs to fix api compat errors
Jul 9, 2021
764d246
updating presentationcore return types for heading level
Jul 9, 2021
ee46685
Revert "changing location of automationheadinglevel.cs to fix api com…
Jul 9, 2021
c203d9e
maintaining the values of the enum as this for further testing
Jul 9, 2021
9ebec44
Update src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Wind…
guimafelipe Jul 9, 2021
cdf3786
changing enums to start on 0 and fixing automaticalli added code
Jul 9, 2021
a4df4cd
first try to add enum mapping
Jul 10, 2021
0b283ac
removing unreachable code
Jul 12, 2021
1ae4a20
moving the headinglevel conversion to automarionpeer.cs
Jul 12, 2021
d29ff29
removing api compat error
Jul 14, 2021
7ef5140
moving headinglevel ids enum to only the places where it is necessary
Jul 14, 2021
f7f4ff4
reverting baseline files
Jul 15, 2021
1c09b7d
removing disclaimer
Jul 15, 2021
c113364
removing switches
Jul 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@
<Compile Include="System\Windows\UIElement3D.cs" />
<Compile Include="System\Windows\UIPropertyMetadata.cs" />
<Compile Include="System\Windows\Automation\AutomationLiveSetting.cs" />
<Compile Include="System\Windows\Automation\AutomationHeadingLevel.cs" />
<Compile Include="System\Windows\Automation\AutomationProperties.cs" />
<Compile Include="System\Windows\Automation\IsOffscreenBehavior.cs" />
<Compile Include="System\Windows\Automation\Peers\AutomationPeer.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//
//
//
// Description: Enumeration for possible values of AutomationProperties.HeadingLevel
//

namespace System.Windows.Automation
{
/// <summary>
/// Describes the heading level of a control
/// </summary>
public enum AutomationHeadingLevel
{
/// <summary>
/// The element does not have a heading level
/// </summary>
None = 0,

/// <summary>
/// The element has a heading level of 1
/// </summary>
Level1,

/// <summary>
/// The element has a heading level of 2
/// </summary>
Level2,

/// <summary>
/// The element has a heading level of 3
/// </summary>
Level3,

/// <summary>
/// The element has a heading level of 4
/// </summary>
Level4,

/// <summary>
/// The element has a heading level of 5
/// </summary>
Level5,

/// <summary>
/// The element has a heading level of 6
/// </summary>
Level6,

/// <summary>
/// The element has a heading level of 7
/// </summary>
Level7,

/// <summary>
/// The element has a heading level of 8
/// </summary>
Level8,

/// <summary>
/// The element has a heading level of 9
/// </summary>
Level9,
}

guimafelipe marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,75 @@ public static int GetSizeOfSet(DependencyObject element)
}
#endregion

#region HeadingLevel
public static readonly DependencyProperty HeadingLevelProperty =
DependencyProperty.RegisterAttached(
"HeadingLevel",
typeof(AutomationHeadingLevel),
typeof(AutomationProperties),
new UIPropertyMetadata(AutomationHeadingLevel.None));

/// <summary>
/// Helper for setting HeadingLevel property on a DependencyObject.
/// </summary>
public static void SetHeadingLevel(DependencyObject element, AutomationHeadingLevel value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}

element.SetValue(HeadingLevelProperty, value);
}

/// <summary>
/// Helper for reading HeadingLevel property from a DependencyObject.
/// </summary>
public static AutomationHeadingLevel GetHeadingLevel(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}

return ((AutomationHeadingLevel)element.GetValue(HeadingLevelProperty));
}
#endregion

#region isDialog
public static readonly DependencyProperty IsDialogProperty =
DependencyProperty.RegisterAttached(
"IsDialog",
typeof(bool),
typeof(AutomationProperties),
new UIPropertyMetadata(false));

/// <summary>
/// Helper for setting IsDialog property on a DependencyObject.
/// </summary>
public static void SetIsDialog(DependencyObject element, bool value)
{
if(element == null)
{
throw new ArgumentNullException(nameof(element));
}
element.SetValue(IsDialogProperty, value);
}

/// <summary>
/// Helper for reading IsDialog property from a DependencyObject.
guimafelipe marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public static bool GetIsDialog(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}

return (bool)element.GetValue(IsDialogProperty);
}
#endregion

#region private implementation
// Validation callback for string properties
private static bool IsNotNull(object value)
Expand All @@ -608,4 +677,3 @@ private static bool IsNotNull(object value)
#endregion
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,11 @@ virtual protected string GetLocalizedControlTypeCore()
///
abstract protected bool IsControlElementCore();

///
virtual protected bool IsDialogCore(){
return false;
}

///
abstract protected AutomationPeer GetLabeledByCore();

Expand Down Expand Up @@ -703,6 +708,13 @@ virtual protected int GetPositionInSetCore()
return AutomationProperties.AutomationPositionInSetDefault;
}

/// <summary>
guimafelipe marked this conversation as resolved.
Show resolved Hide resolved
/// Override this method to provide UIAutomation with the heading level of this element.
/// </summary>
virtual protected AutomationHeadingLevel GetHeadingLevelCore()
{
return AutomationHeadingLevel.None;
}

//
// INTERNAL STUFF - NOT OVERRIDABLE
Expand Down Expand Up @@ -1263,6 +1275,104 @@ public int GetSizeOfSet()
return result;
}

/// <summary>
guimafelipe marked this conversation as resolved.
Show resolved Hide resolved
/// Attempt to get the value for the HeadingLevel property.
/// </summary>
/// <remarks>
/// This public call cannot be attempted if another public call is in progress.
/// </remarks>
/// <returns>
/// The value for the HeadingLevel property.
/// </returns>
public AutomationHeadingLevel GetHeadingLevel()
{
AutomationHeadingLevel result = AutomationHeadingLevel.None;

if (_publicCallInProgress)
throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

try
{
_publicCallInProgress = true;
result = GetHeadingLevelCore();
}
finally
{
_publicCallInProgress = false;
}
return result;
}


private enum HeadingLevel
{
None = 80050,
Level1,
Level2,
Level3,
Level4,
Level5,
Level6,
Level7,
Level8,
Level9,
}
private static HeadingLevel ConvertHeadingLevelToId(AutomationHeadingLevel value){
switch(value)
{
case AutomationHeadingLevel.None:
return HeadingLevel.None;
case AutomationHeadingLevel.Level1:
return HeadingLevel.Level1;
case AutomationHeadingLevel.Level2:
return HeadingLevel.Level2;
case AutomationHeadingLevel.Level3:
return HeadingLevel.Level3;
case AutomationHeadingLevel.Level4:
return HeadingLevel.Level4;
case AutomationHeadingLevel.Level5:
return HeadingLevel.Level5;
case AutomationHeadingLevel.Level6:
return HeadingLevel.Level6;
case AutomationHeadingLevel.Level7:
return HeadingLevel.Level7;
case AutomationHeadingLevel.Level8:
return HeadingLevel.Level8;
case AutomationHeadingLevel.Level9:
return HeadingLevel.Level9;
default:
return HeadingLevel.None;
}
}


/// <summary>
/// Attempt to get the value for the IsDialog property.
/// </summary>
/// <remarks>
/// This public call cannot be attempted if another public call is in progress.
/// </remarks>
/// <returns>
/// The value for the IsDialog property.
/// </returns>
public bool IsDialog()
{
bool result = false;
if(_publicCallInProgress)
throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

try
{
_publicCallInProgress = true;
result = IsDialogCore();
}
finally
{
_publicCallInProgress = false;
}
return result;
}

/// <summary>
/// Attempt to get the value for the PositionInSet property.
/// </summary>
Expand Down Expand Up @@ -1756,7 +1866,7 @@ private void RaisePropertyChangedInternal(IRawElementProviderSimple provider,
#endif
}

// InvalidateLimit – lower bound for raising ChildrenInvalidated StructureChange event
// InvalidateLimit is the lower bound for raising ChildrenInvalidated StructureChange event
internal void UpdateChildrenInternal(int invalidateLimit)
{
List<AutomationPeer> oldChildren = _children;
Expand Down Expand Up @@ -1989,7 +2099,7 @@ internal void UpdateSubtree()

/// <summary>
/// propagate the new value for AncestorsInvalid through the parent chain,
/// use EventSource (wrapper) peers whenever available as it’s the one connected to the tree.
/// use EventSource (wrapper) peers whenever available as it's the one connected to the tree.
/// </summary>
internal void InvalidateAncestorsRecursive()
{
Expand Down Expand Up @@ -2061,6 +2171,10 @@ internal object GetPropertyValue(int propertyId)
if (getProperty != null)
{
result = getProperty(this);
if(AutomationElementIdentifiers.HeadingLevelProperty != null && propertyId == AutomationElementIdentifiers.HeadingLevelProperty.Id)
{
result = ConvertHeadingLevelToId((AutomationHeadingLevel)result);
}
}

return result;
Expand Down Expand Up @@ -2312,6 +2426,14 @@ private static void Initialize()
{
s_propertyInfo[AutomationElementIdentifiers.PositionInSetProperty.Id] = new GetProperty(GetPositionInSet);
}
if (AutomationElementIdentifiers.HeadingLevelProperty != null)
{
s_propertyInfo[AutomationElementIdentifiers.HeadingLevelProperty.Id] = new GetProperty(GetHeadingLevel);
}
if (AutomationElementIdentifiers.IsDialogProperty != null)
{
s_propertyInfo[AutomationElementIdentifiers.IsDialogProperty.Id] = new GetProperty(IsDialog);
}
}

private delegate object WrapObject(AutomationPeer peer, object iface);
Expand Down Expand Up @@ -2363,6 +2485,8 @@ internal PatternInfo(int id, WrapObject wrapObject, PatternInterface patternInte
private static object GetControllerFor(AutomationPeer peer) { return peer.GetControllerForProviderArray(); }
private static object GetSizeOfSet(AutomationPeer peer) { return peer.GetSizeOfSet(); }
private static object GetPositionInSet(AutomationPeer peer) { return peer.GetPositionInSet(); }
private static object GetHeadingLevel(AutomationPeer peer) { return peer.GetHeadingLevel(); }
guimafelipe marked this conversation as resolved.
Show resolved Hide resolved
private static object IsDialog(AutomationPeer peer) { return peer.IsDialog(); }

private static Hashtable s_patternInfo;
private static Hashtable s_propertyInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ override protected bool IsEnabledCore()
return _owner.IsEnabled;
}

/// <summary>
/// <see cref="AutomationPeer.IsDialogCore"/>
/// </summary>
override protected bool IsDialogCore()
{
return AutomationProperties.GetIsDialog(_owner);
}

/// <summary>
/// <see cref="AutomationPeer.IsPasswordCore"/>
/// </summary>
Expand Down Expand Up @@ -287,6 +295,15 @@ override protected int GetSizeOfSetCore()
return AutomationProperties.GetSizeOfSet(_owner);
}

/// <summary>
/// Provides a value for UIAutomation's HeadingLevel property
/// Reads <see cref="AutomationProperties.HeadingLevelProperty"/> and returns the value
/// </summary>
override protected AutomationHeadingLevel GetHeadingLevelCore()
{
return AutomationProperties.GetHeadingLevel(_owner);
}

/// <summary>
/// <see cref="AutomationPeer.GetClickablePointCore"/>
/// </summary>
Expand Down
Loading