From: <ho...@us...> - 2008-04-25 11:47:52
|
Revision: 13192 http://bibdesk.svn.sourceforge.net/bibdesk/?rev=13192&view=rev Author: hofman Date: 2008-04-25 04:47:57 -0700 (Fri, 25 Apr 2008) Log Message: ----------- Add accessibility support for file view. Icons have link role, as FinderItem is not public. Modified Paths: -------------- trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.m trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.xcodeproj/project.pbxproj Added Paths: ----------- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.h trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.m Added: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.h =================================================================== --- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.h (rev 0) +++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.h 2008-04-25 11:47:57 UTC (rev 13192) @@ -0,0 +1,58 @@ +// +// FVAccessibilityIconElement.h +// FileView +// +// Created by Christiaan Hofman on 4/25/08. +/* + This software is Copyright (c) 2008 + Christiaan Hofman. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of Christiaan Hofman nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + + +@interface FVAccessibilityIconElement : NSObject { + NSUInteger _index; + id _parent; +} ++ (id)elementWithIndex:(NSUInteger)anIndex parent:(id)aParent; +- (id)initWithIndex:(NSUInteger)anIndex parent:(id)aParent; +- (NSUInteger)index; +@end + + +@interface NSObject (FVAccessibilityIconElementParent) +- (NSURL *)URLForIconElement:(id)element; +- (NSRect)screenRectForIconElement:(id)element; +- (BOOL)isIconElementSelected:(id)element; +- (void)setSelected:(BOOL)selected forIconElement:(id)element; +- (void)openIconElement:(id)element; +@end Added: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.m =================================================================== --- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.m (rev 0) +++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVAccessibilityIconElement.m 2008-04-25 11:47:57 UTC (rev 13192) @@ -0,0 +1,170 @@ +// +// FVAccessibilityIconElement.m +// FileView +// +// Created by Christiaan Hofman on 4/25/08. +/* + This software is Copyright (c) 2008 + Christiaan Hofman. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of Christiaan Hofman nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "FVAccessibilityIconElement.h" + + +@implementation FVAccessibilityIconElement + ++ (id)elementWithIndex:(NSUInteger)anIndex parent:(id)aParent; +{ + return [[[self alloc] initWithIndex:anIndex parent:aParent] autorelease]; +} + +- (id)initWithIndex:(NSUInteger)anIndex parent:(id)aParent; +{ + if (self = [super init]) { + _index = anIndex; + _parent = aParent; + } + return self; +} + +- (BOOL)isEqual:(id)other { + if ([other isKindOfClass:[FVAccessibilityIconElement class]]) { + FVAccessibilityIconElement *otherElement = (FVAccessibilityIconElement *)other; + return _index == otherElement->_index && _parent == otherElement->_parent; + } else { + return NO; + } +} + +- (unsigned int)hash { + return _index + [_parent hash]; +} + +- (NSUInteger)index { + return _index; +} + +- (NSArray *)accessibilityAttributeNames { + static NSArray *attributes = nil; + if (attributes == nil) { + attributes = [[NSArray alloc] initWithObjects: + NSAccessibilityRoleAttribute, + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityTitleAttribute, + NSAccessibilityURLAttribute, + NSAccessibilityParentAttribute, + NSAccessibilityWindowAttribute, + NSAccessibilityTopLevelUIElementAttribute, + NSAccessibilityFocusedAttribute, + NSAccessibilityEnabledAttribute, + NSAccessibilityPositionAttribute, + NSAccessibilitySizeAttribute, + nil]; + } + return attributes; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute { + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { + return NSAccessibilityLinkRole; + } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { + return NSAccessibilityRoleDescription(NSAccessibilityLinkRole, nil); + } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) { + return NSAccessibilityUnignoredAncestor(_parent); + } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) { + // We're in the same window as our parent. + return [NSAccessibilityUnignoredAncestor(_parent) accessibilityAttributeValue:NSAccessibilityWindowAttribute]; + } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) { + // We're in the same top level element as our parent. + return [NSAccessibilityUnignoredAncestor(_parent) accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; + } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { + return [NSValue valueWithPoint:[_parent screenRectForIconElement:self].origin]; + } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) { + return [NSValue valueWithSize:[_parent screenRectForIconElement:self].size]; + } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) { + NSString *title; + NSURL *aURL = [_parent URLForIconElement:self]; + if ([aURL isFileURL]) { + if (noErr == LSCopyDisplayNameForURL((CFURLRef)aURL, (CFStringRef *)&title)) + title = [title autorelease]; + else + title = [[aURL path] lastPathComponent]; + } else { + title = [[aURL absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + return title; + } else if ([attribute isEqualToString:NSAccessibilityURLAttribute]) { + return [_parent URLForIconElement:self]; + } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) { + return [NSNumber numberWithBool:YES]; + } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + return [NSNumber numberWithBool:[_parent isIconElementSelected:self]]; + } else { + return nil; + } +} + +- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + return [attribute isEqualToString:NSAccessibilityFocusedAttribute]; +} + +- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + [_parent setSelected:[value boolValue] forIconElement:self]; + } +} + +- (BOOL)accessibilityIsIgnored { + return NO; +} + +- (id)accessibilityHitTest:(NSPoint)point { + return NSAccessibilityUnignoredAncestor(self); +} + +- (id)accessibilityFocusedUIElement { + return NSAccessibilityUnignoredAncestor(self); +} + +- (NSArray *)accessibilityActionNames { + return [NSArray arrayWithObjects:NSAccessibilityPressAction, nil]; +} + +- (NSString *)accessibilityActionDescription:(NSString *)anAction { + return NSAccessibilityActionDescription(anAction); +} + +- (void)accessibilityPerformAction:(NSString *)anAction { + if ([anAction isEqualToString:NSAccessibilityPressAction]) + [_parent openIconElement:self]; +} + +@end Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.m =================================================================== --- trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.m 2008-04-25 05:45:28 UTC (rev 13191) +++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.m 2008-04-25 11:47:57 UTC (rev 13192) @@ -52,6 +52,7 @@ #import "FVSlider.h" #import "FVColorMenuView.h" #import "FVBitmapContextCache.h" +#import "FVAccessibilityIconElement.h" static NSString *FVWeblocFilePboardType = @"CorePasteboardFlavorType 0x75726C20"; @@ -3009,4 +3010,88 @@ } } +#pragma mark Accessibility + +- (NSArray *)accessibilityAttributeNames { + static NSArray *attributes = nil; + if (attributes == nil) + attributes = [[[super accessibilityAttributeNames] arrayByAddingObject:NSAccessibilityChildrenAttribute] retain]; + return attributes; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute { + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { + return NSAccessibilityGroupRole; + } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { + return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil); + } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + NSMutableArray *children = [NSMutableArray array]; + NSUInteger i, count = [self numberOfIcons]; + for (i = 0; i < count; i++) + [children addObject:[FVAccessibilityIconElement elementWithIndex:i parent:self]]; + return NSAccessibilityUnignoredChildren(children); + } else { + return [super accessibilityAttributeValue:attribute]; + } +} + +- (BOOL)accessibilityIsIgnored { + return NO; +} + +- (id)accessibilityHitTest:(NSPoint)point { + NSUInteger i, r, c; + NSPoint localPoint = [self convertPoint:[[self window] convertScreenToBase:point] fromView:nil]; + if ([self _getGridRow:&r column:&c atPoint:localPoint]) { + i = [self _indexForGridRow:r column:c]; + if (i != NSNotFound) + return [[FVAccessibilityIconElement elementWithIndex:i parent:self] accessibilityHitTest:point]; + } + return NSAccessibilityUnignoredAncestor(self); +} + +- (id)accessibilityFocusedUIElement { + NSUInteger i = [_selectedIndexes firstIndex]; + if (i != NSNotFound) + return [[FVAccessibilityIconElement elementWithIndex:i parent:self] accessibilityFocusedUIElement]; + else + return NSAccessibilityUnignoredAncestor(self); +} + +- (NSURL *)URLForIconElement:(id)element { + return [self iconURLAtIndex:[element index]]; +} + +- (NSRect)screenRectForIconElement:(id)element { + NSRect rect = NSZeroRect; + NSUInteger r, c; + if ([self _getGridRow:&r column:&c ofIndex:[element index]]) { + rect = [self _rectOfIconInRow:r column:c]; + rect = [self convertRect:rect toView:nil]; + rect.origin = [[self window] convertBaseToScreen:rect.origin]; + } + return rect; +} + +- (BOOL)isIconElementSelected:(id)element { + return [[self selectionIndexes] containsIndex:[element index]]; +} + +- (void)setSelected:(BOOL)selected forIconElement:(id)element { + NSMutableIndexSet *indexes = [[self selectionIndexes] mutableCopy]; + NSUInteger i = [element index]; + if (selected && [indexes containsIndex:i] == NO) { + [indexes addIndex:i]; + [self setSelectionIndexes:indexes]; + } else if (selected == NO && [indexes containsIndex:i]) { + [indexes removeIndex:i]; + [self setSelectionIndexes:indexes]; + } + [indexes release]; +} + +- (void)openIconElement:(id)element { + [self _openURLs:[NSArray arrayWithObjects:[self iconURLAtIndex:[element index]], nil]]; +} + @end Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.xcodeproj/project.pbxproj =================================================================== --- trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.xcodeproj/project.pbxproj 2008-04-25 05:45:28 UTC (rev 13191) +++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FileView.xcodeproj/project.pbxproj 2008-04-25 11:47:57 UTC (rev 13192) @@ -61,6 +61,8 @@ CE89233D0D7CBB18006D514C /* FVInvocationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CE05D5E70D7C22550034C2A8 /* FVInvocationOperation.m */; }; CE89233E0D7CBB19006D514C /* FVOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = CE05D5E80D7C22550034C2A8 /* FVOperation.h */; }; CE89233F0D7CBB1A006D514C /* FVOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CE05D5E90D7C22550034C2A8 /* FVOperation.m */; }; + CEA831140DC1FAB500B551D1 /* FVAccessibilityIconElement.h in Headers */ = {isa = PBXBuildFile; fileRef = CEA831120DC1FAB500B551D1 /* FVAccessibilityIconElement.h */; }; + CEA831150DC1FAB500B551D1 /* FVAccessibilityIconElement.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA831130DC1FAB500B551D1 /* FVAccessibilityIconElement.m */; }; F92C7BC70D280D0E004409D8 /* FVWebViewIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = F92C7BAA0D280626004409D8 /* FVWebViewIcon.h */; }; F92C7BC80D280D0F004409D8 /* FVWebViewIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C7BAB0D280626004409D8 /* FVWebViewIcon.m */; }; F92C7C4F0D282503004409D8 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C7C4E0D282503004409D8 /* SystemConfiguration.framework */; }; @@ -238,6 +240,8 @@ CE05D5E70D7C22550034C2A8 /* FVInvocationOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FVInvocationOperation.m; sourceTree = "<group>"; }; CE05D5E80D7C22550034C2A8 /* FVOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FVOperation.h; sourceTree = "<group>"; }; CE05D5E90D7C22550034C2A8 /* FVOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FVOperation.m; sourceTree = "<group>"; }; + CEA831120DC1FAB500B551D1 /* FVAccessibilityIconElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FVAccessibilityIconElement.h; sourceTree = "<group>"; }; + CEA831130DC1FAB500B551D1 /* FVAccessibilityIconElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FVAccessibilityIconElement.m; sourceTree = "<group>"; }; F92C7BAA0D280626004409D8 /* FVWebViewIcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FVWebViewIcon.h; sourceTree = "<group>"; }; F92C7BAB0D280626004409D8 /* FVWebViewIcon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FVWebViewIcon.m; sourceTree = "<group>"; }; F92C7C4E0D282503004409D8 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; }; @@ -425,6 +429,8 @@ CE05D5CC0D7C21E30034C2A8 /* Queueing */, CE05D5CD0D7C22070034C2A8 /* Operations */, CE05D48B0D7B38B20034C2A8 /* Caching */, + CEA831120DC1FAB500B551D1 /* FVAccessibilityIconElement.h */, + CEA831130DC1FAB500B551D1 /* FVAccessibilityIconElement.m */, CE05D3C40D7B272A0034C2A8 /* FVDownload.h */, CE05D3C50D7B272A0034C2A8 /* FVDownload.m */, F93C3AE90D39473C006EB558 /* FVFinderLabel.h */, @@ -672,6 +678,7 @@ CE89233A0D7CBB16006D514C /* FVIconOperation.h in Headers */, CE89233C0D7CBB17006D514C /* FVInvocationOperation.h in Headers */, CE89233E0D7CBB19006D514C /* FVOperation.h in Headers */, + CEA831140DC1FAB500B551D1 /* FVAccessibilityIconElement.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -854,6 +861,7 @@ CE89233B0D7CBB17006D514C /* FVIconOperation.m in Sources */, CE89233D0D7CBB18006D514C /* FVInvocationOperation.m in Sources */, CE89233F0D7CBB1A006D514C /* FVOperation.m in Sources */, + CEA831150DC1FAB500B551D1 /* FVAccessibilityIconElement.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |