michael@0: /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #import "mozActionElements.h" michael@0: michael@0: #import "MacUtils.h" michael@0: #include "Accessible-inl.h" michael@0: #include "DocAccessible.h" michael@0: #include "XULTabAccessible.h" michael@0: michael@0: #include "nsDeckFrame.h" michael@0: #include "nsObjCExceptions.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: enum CheckboxValue { michael@0: // these constants correspond to the values in the OS michael@0: kUnchecked = 0, michael@0: kChecked = 1, michael@0: kMixed = 2 michael@0: }; michael@0: michael@0: @implementation mozButtonAccessible michael@0: michael@0: - (NSArray*)accessibilityAttributeNames michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: static NSArray *attributes = nil; michael@0: if (!attributes) { michael@0: attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required michael@0: NSAccessibilityRoleAttribute, // required michael@0: NSAccessibilityRoleDescriptionAttribute, michael@0: NSAccessibilityPositionAttribute, // required michael@0: NSAccessibilitySizeAttribute, // required michael@0: NSAccessibilityWindowAttribute, // required michael@0: NSAccessibilityPositionAttribute, // required michael@0: NSAccessibilityTopLevelUIElementAttribute, // required michael@0: NSAccessibilityHelpAttribute, michael@0: NSAccessibilityEnabledAttribute, // required michael@0: NSAccessibilityFocusedAttribute, // required michael@0: NSAccessibilityTitleAttribute, // required michael@0: NSAccessibilityDescriptionAttribute, michael@0: #if DEBUG michael@0: @"AXMozDescription", michael@0: #endif michael@0: nil]; michael@0: } michael@0: return attributes; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (id)accessibilityAttributeValue:(NSString *)attribute michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) michael@0: return nil; michael@0: if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { michael@0: if ([self isTab]) michael@0: return utils::LocalizedString(NS_LITERAL_STRING("tab")); michael@0: michael@0: return NSAccessibilityRoleDescription([self role], nil); michael@0: } michael@0: michael@0: return [super accessibilityAttributeValue:attribute]; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (BOOL)accessibilityIsIgnored michael@0: { michael@0: return !mGeckoAccessible; michael@0: } michael@0: michael@0: - (NSArray*)accessibilityActionNames michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([self isEnabled]) michael@0: return [NSArray arrayWithObject:NSAccessibilityPressAction]; michael@0: michael@0: return nil; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (NSString*)accessibilityActionDescription:(NSString*)action michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([action isEqualToString:NSAccessibilityPressAction]) { michael@0: if ([self isTab]) michael@0: return utils::LocalizedString(NS_LITERAL_STRING("switch")); michael@0: michael@0: return @"press button"; // XXX: localize this later? michael@0: } michael@0: michael@0: return nil; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (void)accessibilityPerformAction:(NSString*)action michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK; michael@0: michael@0: if ([action isEqualToString:NSAccessibilityPressAction]) michael@0: [self click]; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK; michael@0: } michael@0: michael@0: - (void)click michael@0: { michael@0: // both buttons and checkboxes have only one action. we should really stop using arbitrary michael@0: // arrays with actions, and define constants for these actions. michael@0: mGeckoAccessible->DoAction(0); michael@0: } michael@0: michael@0: - (BOOL)isTab michael@0: { michael@0: return (mGeckoAccessible && (mGeckoAccessible->Role() == roles::PAGETAB)); michael@0: } michael@0: michael@0: @end michael@0: michael@0: @implementation mozCheckboxAccessible michael@0: michael@0: - (NSString*)accessibilityActionDescription:(NSString*)action michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([action isEqualToString:NSAccessibilityPressAction]) { michael@0: if ([self isChecked] != kUnchecked) michael@0: return @"uncheck checkbox"; // XXX: localize this later? michael@0: michael@0: return @"check checkbox"; // XXX: localize this later? michael@0: } michael@0: michael@0: return nil; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (int)isChecked michael@0: { michael@0: uint64_t state = mGeckoAccessible->NativeState(); michael@0: michael@0: // check if we're checked or in a mixed state michael@0: if (state & states::CHECKED) { michael@0: return (state & states::MIXED) ? kMixed : kChecked; michael@0: } michael@0: michael@0: return kUnchecked; michael@0: } michael@0: michael@0: - (id)value michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: return [NSNumber numberWithInt:[self isChecked]]; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: @end michael@0: michael@0: @implementation mozPopupButtonAccessible michael@0: michael@0: - (NSArray *)accessibilityAttributeNames michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: static NSArray *attributes = nil; michael@0: michael@0: if (!attributes) { michael@0: attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required michael@0: NSAccessibilityPositionAttribute, // required michael@0: NSAccessibilityRoleAttribute, // required michael@0: NSAccessibilitySizeAttribute, // required michael@0: NSAccessibilityWindowAttribute, // required michael@0: NSAccessibilityTopLevelUIElementAttribute, // required michael@0: NSAccessibilityHelpAttribute, michael@0: NSAccessibilityEnabledAttribute, // required michael@0: NSAccessibilityFocusedAttribute, // required michael@0: NSAccessibilityTitleAttribute, // required for popupmenus, and for menubuttons with a title michael@0: NSAccessibilityChildrenAttribute, // required michael@0: NSAccessibilityDescriptionAttribute, // required if it has no title attr michael@0: #if DEBUG michael@0: @"AXMozDescription", michael@0: #endif michael@0: nil]; michael@0: } michael@0: return attributes; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (id)accessibilityAttributeValue:(NSString *)attribute michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { michael@0: return [super children]; michael@0: } michael@0: return [super accessibilityAttributeValue:attribute]; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (NSArray *)accessibilityActionNames michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([self isEnabled]) { michael@0: return [NSArray arrayWithObjects:NSAccessibilityPressAction, michael@0: NSAccessibilityShowMenuAction, michael@0: nil]; michael@0: } michael@0: return nil; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (NSString *)accessibilityActionDescription:(NSString *)action michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: if ([action isEqualToString:NSAccessibilityShowMenuAction]) michael@0: return @"show menu"; michael@0: return [super accessibilityActionDescription:action]; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: - (void)accessibilityPerformAction:(NSString *)action michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK; michael@0: michael@0: // both the ShowMenu and Click action do the same thing. michael@0: if ([self isEnabled]) { michael@0: // TODO: this should bring up the menu, but currently doesn't. michael@0: // once msaa and atk have merged better, they will implement michael@0: // the action needed to show the menu. michael@0: [super click]; michael@0: } michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK; michael@0: } michael@0: michael@0: @end michael@0: michael@0: @implementation mozTabsAccessible michael@0: michael@0: - (void)dealloc michael@0: { michael@0: [mTabs release]; michael@0: michael@0: [super dealloc]; michael@0: } michael@0: michael@0: - (NSArray*)accessibilityAttributeNames michael@0: { michael@0: // standard attributes that are shared and supported by root accessible (AXMain) elements. michael@0: static NSMutableArray* attributes = nil; michael@0: michael@0: if (!attributes) { michael@0: attributes = [[super accessibilityAttributeNames] mutableCopy]; michael@0: [attributes addObject:NSAccessibilityContentsAttribute]; michael@0: [attributes addObject:NSAccessibilityTabsAttribute]; michael@0: } michael@0: michael@0: return attributes; michael@0: } michael@0: michael@0: - (id)accessibilityAttributeValue:(NSString *)attribute michael@0: { michael@0: if ([attribute isEqualToString:NSAccessibilityContentsAttribute]) michael@0: return [super children]; michael@0: if ([attribute isEqualToString:NSAccessibilityTabsAttribute]) michael@0: return [self tabs]; michael@0: michael@0: return [super accessibilityAttributeValue:attribute]; michael@0: } michael@0: michael@0: /** michael@0: * Returns the selected tab (the mozAccessible) michael@0: */ michael@0: - (id)value michael@0: { michael@0: if (!mGeckoAccessible) michael@0: return nil; michael@0: michael@0: Accessible* accessible = mGeckoAccessible->GetSelectedItem(0); michael@0: if (!accessible) michael@0: return nil; michael@0: michael@0: mozAccessible* nativeAcc = nil; michael@0: nsresult rv = accessible->GetNativeInterface((void**)&nativeAcc); michael@0: NS_ENSURE_SUCCESS(rv, nil); michael@0: michael@0: return nativeAcc; michael@0: } michael@0: michael@0: /** michael@0: * Return the mozAccessibles that are the tabs. michael@0: */ michael@0: - (id)tabs michael@0: { michael@0: if (mTabs) michael@0: return mTabs; michael@0: michael@0: NSArray* children = [self children]; michael@0: NSEnumerator* enumerator = [children objectEnumerator]; michael@0: mTabs = [[NSMutableArray alloc] init]; michael@0: michael@0: id obj; michael@0: while ((obj = [enumerator nextObject])) michael@0: if ([obj isTab]) michael@0: [mTabs addObject:obj]; michael@0: michael@0: return mTabs; michael@0: } michael@0: michael@0: - (void)invalidateChildren michael@0: { michael@0: [super invalidateChildren]; michael@0: michael@0: [mTabs release]; michael@0: mTabs = nil; michael@0: } michael@0: michael@0: @end michael@0: michael@0: @implementation mozPaneAccessible michael@0: michael@0: - (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute michael@0: { michael@0: if (!mGeckoAccessible) michael@0: return 0; michael@0: michael@0: // By default this calls -[[mozAccessible children] count]. michael@0: // Since we don't cache mChildren. This is faster. michael@0: if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) michael@0: return mGeckoAccessible->ChildCount() ? 1 : 0; michael@0: michael@0: return [super accessibilityArrayAttributeCount:attribute]; michael@0: } michael@0: michael@0: - (NSArray*)children michael@0: { michael@0: if (!mGeckoAccessible) michael@0: return nil; michael@0: michael@0: nsDeckFrame* deckFrame = do_QueryFrame(mGeckoAccessible->GetFrame()); michael@0: nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nullptr; michael@0: michael@0: Accessible* selectedAcc = nullptr; michael@0: if (selectedFrame) { michael@0: nsINode* node = selectedFrame->GetContent(); michael@0: selectedAcc = mGeckoAccessible->Document()->GetAccessible(node); michael@0: } michael@0: michael@0: if (selectedAcc) { michael@0: mozAccessible *curNative = GetNativeFromGeckoAccessible(selectedAcc); michael@0: if (curNative) michael@0: return [NSArray arrayWithObjects:GetObjectOrRepresentedView(curNative), nil]; michael@0: } michael@0: michael@0: return nil; michael@0: } michael@0: michael@0: @end