1 /* Copyright (c) 2006-2007 Christopher J. W. Lloyd
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
9 #import <AppKit/NSComboBoxCell.h>
10 #import <AppKit/NSButtonCell.h>
11 #import <AppKit/NSComboBoxWindow.h>
12 #import <Foundation/NSKeyedArchiver.h>
13 #import <AppKit/NSGraphicsStyle.h>
14 #import <AppKit/NSRaise.h>
16 @implementation NSComboBoxCell
18 -(void)encodeWithCoder:(NSCoder *)coder {
19 NSUnimplementedMethod();
22 -initWithCoder:(NSCoder *)coder {
23 [super initWithCoder:coder];
25 if([coder allowsKeyedCoding]){
26 NSKeyedUnarchiver *keyed=(NSKeyedUnarchiver *)coder;
28 _dataSource=[keyed decodeObjectForKey:@"NSDataSource"];
29 _objectValues=[[NSMutableArray alloc] initWithArray:[keyed decodeObjectForKey:@"NSPopUpListData"]];
30 _numberOfVisibleItems=[keyed decodeIntForKey:@"NSVisibleItemCount"];
31 _usesDataSource=[keyed decodeBoolForKey:@"NSUsesDataSource"];
32 _hasVerticalScroller=[keyed decodeBoolForKey:@"NSHasVerticalScroller"];
33 _completes=[keyed decodeBoolForKey:@"NSCompletes"];
34 _isButtonBordered=YES;
39 [NSException raise:NSInvalidArgumentException format:@"-[%@ %s] is not implemented for coder %@",isa,sel_getName(_cmd),coder];
46 [_dataSource release];
47 [_objectValues release];
51 -copyWithZone:(NSZone *)zone {
52 NSComboBoxCell *copy = [super copyWithZone:zone];
54 copy->_objectValues=[_objectValues copy];
63 -(BOOL)usesDataSource {
64 return _usesDataSource;
67 -(BOOL)isButtonBordered {
68 return _isButtonBordered;
75 -(BOOL)hasVerticalScroller {
76 return _hasVerticalScroller;
79 -(NSSize)intercellSpacing {
80 return _intercellSpacing;
87 -(int)numberOfVisibleItems {
88 return _numberOfVisibleItems;
91 -(void)setDataSource:value {
95 -(void)setUsesDataSource:(BOOL)value {
96 _usesDataSource=value;
99 -(void)setButtonBordered:(BOOL)value {
100 _isButtonBordered=value;
103 -(void)setItemHeight:(float)value {
107 -(void)setHasVerticalScroller:(BOOL)value {
108 _hasVerticalScroller=value;
111 -(void)setIntercellSpacing:(NSSize)value {
112 _intercellSpacing=value;
115 -(void)setCompletes:(BOOL)flag {
119 -(void)setNumberOfVisibleItems:(int)value {
120 _numberOfVisibleItems=value;
123 -(int)numberOfItems {
124 return [_objectValues count];
127 -(NSArray *)objectValues {
128 return _objectValues;
131 -itemObjectValueAtIndex:(int)index {
132 return [_objectValues objectAtIndex:index];
135 -(int)indexOfItemWithObjectValue:(id)object {
136 return [_objectValues indexOfObjectIdenticalTo:object];
139 -(void)addItemWithObjectValue:(id)object {
140 [_objectValues addObject:object];
141 _buttonEnabled=([_objectValues count]>0)?YES:NO;
144 -(void)addItemsWithObjectValues:(NSArray *)objects {
145 [_objectValues addObjectsFromArray:objects];
146 _buttonEnabled=([_objectValues count]>0)?YES:NO;
149 -(void)removeAllItems {
150 [_objectValues removeAllObjects];
151 _buttonEnabled=([_objectValues count]>0)?YES:NO;
154 -(void)removeItemAtIndex:(int)index {
155 [_objectValues removeObjectAtIndex:index];
156 _buttonEnabled=([_objectValues count]>0)?YES:NO;
159 -(void)removeItemWithObjectValue:value {
160 [_objectValues removeObject:value];
161 _buttonEnabled=([_objectValues count]>0)?YES:NO;
164 -(void)insertItemWithObjectValue:(id)object atIndex:(int)index {
165 [_objectValues insertObject:object atIndex:index];
166 _buttonEnabled=([_objectValues count]>0)?YES:NO;
169 -(int)indexOfSelectedItem {
170 int index = [_objectValues indexOfObject:[self objectValue]];
171 return (index != NSNotFound)?index:-1;
174 -objectValueOfSelectedItem {
175 if (!_usesDataSource)
176 return [self objectValue];
179 NSLog(@"*** -[%@ %s] should not be called when usesDataSource is set to YES",isa,sel_getName(_cmd));
184 -(void)selectItemAtIndex:(int)index {
185 if (index < 0 || index >= [_objectValues count])
188 [self setObjectValue:[_objectValues objectAtIndex:index]];
191 -(void)selectItemWithObjectValue:value {
192 if (!_usesDataSource)
194 int index = [_objectValues indexOfObject:value];
195 [self selectItemAtIndex:(index != NSNotFound)?index:-1];
198 NSLog(@"*** -[%@ %s] should not be called when usesDataSource is set to YES",isa,sel_getName(_cmd));
201 -(void)deselectItemAtIndex:(int)index {
202 NSUnimplementedMethod();
205 -(void)scrollItemAtIndexToTop:(int)index {
206 NSUnimplementedMethod();
209 -(void)scrollItemAtIndexToVisible:(int)index {
210 NSUnimplementedMethod();
213 -(void)noteNumberOfItemsChanged {
214 NSUnimplementedMethod();
218 NSUnimplementedMethod();
221 - (NSString *)completedString:(NSString *)string {
222 int i, count = [_objectValues count];
224 if (_usesDataSource == YES) // not supported yet, well...
225 if ([_dataSource respondsToSelector:@selector(comboBoxCell:completedString:)] == YES)
226 return [_dataSource comboBoxCell:self completedString:string];
228 for (i = 0; i < count; ++i) {
229 NSString *stringValue;
231 // NSLog(@"checking %@", [_objectValues objectAtIndex:i]);
232 if ([[_objectValues objectAtIndex:i] isKindOfClass:[NSString class]])
233 stringValue = [_objectValues objectAtIndex:i];
235 stringValue = [[_objectValues objectAtIndex:i] stringValue];
237 if ([stringValue hasPrefix:string])
245 NSSize size=[_controlView frame].size;
251 -(NSRect)buttonRectForBounds:(NSRect)rect {
252 rect.origin.x=(rect.origin.x+rect.size.width)-rect.size.height;
253 rect.size.width=rect.size.height;
257 -(BOOL)trackMouse:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag {
258 NSComboBoxWindow *window;
259 NSPoint origin=[controlView bounds].origin;
260 NSSize size=[self cellSize];
261 NSPoint check=[controlView convertPoint:[event locationInWindow] fromView:nil];
262 unsigned selectedIndex = [_objectValues indexOfObject:[self objectValue]];
264 if([_objectValues count]==0)
267 if(!NSMouseInRect(check,[self buttonRectForBounds:cellFrame],[controlView isFlipped]))
270 origin.y+=size.height;
271 origin=[controlView convertPoint:origin toView:nil];
272 origin=[[controlView window] convertBaseToScreen:origin];
275 window=[[NSComboBoxWindow alloc] initWithFrame:(NSRect){origin,size}];
277 [window setObjectArray:_objectValues];
278 [window setSelectedIndex:selectedIndex];
279 if([self font] != nil)
280 [window setFont:[self font]];
283 [window makeKeyAndOrderFront:self];
284 selectedIndex = [window runTrackingWithEvent:event];
285 [window close]; // release when closed=YES
288 if (selectedIndex != NSNotFound)
290 NSTextView *editor = [controlView currentEditor];
291 NSObject *object = [_objectValues objectAtIndex:selectedIndex];
292 if (editor && object)
294 NSString *string = nil;
295 NSAttributedString *attstr = nil;
298 string = [_formatter stringForObjectValue:object];
301 if ([object isKindOfClass:[NSString class]])
303 else if ([object isKindOfClass:[NSAttributedString class]])
304 if ([editor isRichText])
307 string = [object string];
308 else if ([object respondsToSelector:@selector(descriptionWithLocale:)])
309 string = [object descriptionWithLocale:[NSLocale currentLocale]];
310 else if ([object respondsToSelector:@selector(description)])
311 string = [object description];
316 [[(NSTextView *)editor textStorage] setAttributedString:attstr];
318 [editor setString:string];
320 [editor setSelectedRange:NSMakeRange(0, [[editor string] length])];
321 [self endEditing:editor];
322 if (_sendsActionOnEndEditing)
323 [(NSControl *)controlView sendAction:[(NSControl *)controlView action] to:[(NSControl *)controlView target]];
330 -(NSRect)titleRectForBounds:(NSRect)rect {
331 // Keep some room for the button
332 NSRect buttonFrame = [self buttonRectForBounds:rect];
333 rect.size.width = NSMinX(buttonFrame) - rect.origin.x;
334 rect=[super titleRectForBounds:rect];
339 -(void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)controlView {
340 frame.size = [self cellSize];
341 [super drawInteriorWithFrame:frame inView:controlView];
344 -(void)drawWithFrame:(NSRect)frame inView:(NSView *)controlView {
345 frame.size = [self cellSize];
346 [super drawWithFrame:frame inView:controlView];
348 [[controlView graphicsStyle] drawComboBoxButtonInRect:[self buttonRectForBounds:frame] enabled:_buttonEnabled bordered:_isButtonBordered pressed:_buttonPressed];