53 CPMenu _searchMenuTemplate;
60 BOOL _sendsWholeSearchString;
61 BOOL _sendsSearchStringImmediately;
62 BOOL _canResignFirstResponder;
83 - (id)initWithFrame:(CGRect)frame
85 if (
self = [super initWithFrame:
frame])
88 _sendsWholeSearchString = NO;
89 _sendsSearchStringImmediately = NO;
90 _recentsAutosaveName = nil;
94 _cancelButton._DOMElement.style.cursor =
"default";
95 _searchButton._DOMElement.style.cursor =
"default";
106 [
self setBezeled:YES];
107 [
self setBezelStyle:CPTextFieldRoundedBezel];
108 [
self setBordered:YES];
109 [
self setEditable:YES];
110 [
self setContinuous:YES];
112 var bounds = [
self bounds],
113 cancelButton = [[
CPButton alloc] initWithFrame:[
self cancelButtonRectForBounds:bounds]],
114 searchButton = [[
CPButton alloc] initWithFrame:[
self searchButtonRectForBounds:bounds]];
116 [
self setCancelButton:cancelButton];
117 [
self resetCancelButton];
119 [
self setSearchButton:searchButton];
120 [
self resetSearchButton];
122 _canResignFirstResponder = YES;
125 - (void)viewWillMoveToSuperview:(
CPView)aView
144 if (button != _searchButton)
146 [_searchButton removeFromSuperview];
147 _searchButton = button;
150 [_searchButton setAutoresizingMask:CPViewMaxXMargin];
161 return _searchButton;
168 - (void)resetSearchButton
175 [button
setImage:searchButtonImage];
185 if (button != _cancelButton)
187 [_cancelButton removeFromSuperview];
188 _cancelButton = button;
191 [_cancelButton setAutoresizingMask:CPViewMinXMargin];
192 [_cancelButton setTarget:self];
193 [_cancelButton setAction:@selector(cancelOperation:)];
194 [
self _updateCancelButtonVisibility];
205 return _cancelButton;
212 - (void)resetCancelButton
217 [button
setImage:CPSearchFieldCancelImage];
231 - (CGRect)searchTextRectForBounds:(CGRect)rect
234 width = _CGRectGetWidth(rect),
240 leftOffset = _CGRectGetMaxX(searchBounds) + 2;
246 width = _CGRectGetMinX(cancelRect) - leftOffset;
249 return _CGRectMake(leftOffset, _CGRectGetMinY(rect),
width, _CGRectGetHeight(rect));
257 - (CGRect)searchButtonRectForBounds:(CGRect)rect
267 - (CGRect)cancelButtonRectForBounds:(CGRect)rect
279 return _searchMenuTemplate;
287 - (void)setSearchMenuTemplate:(
CPMenu)aMenu
289 _searchMenuTemplate = aMenu;
292 [
self _loadRecentSearchList];
293 [
self _updateSearchMenu];
301 - (BOOL)sendsWholeSearchString
303 return _sendsWholeSearchString;
310 - (void)setSendsWholeSearchString:(BOOL)flag
312 _sendsWholeSearchString = flag;
319 - (BOOL)sendsSearchStringImmediately
321 return _sendsSearchStringImmediately;
328 - (void)setSendsSearchStringImmediately:(BOOL)flag
330 _sendsSearchStringImmediately = flag;
338 - (int)maximumRecents
340 return _maximumRecents;
347 - (void)setMaximumRecents:(
int)max
354 _maximumRecents = max;
363 return _recentSearches;
373 var max = MIN([
self maximumRecents], [searches count]),
376 _recentSearches = searches;
377 [
self _autosaveRecentSearchList];
386 return _recentsAutosaveName;
395 if (_recentsAutosaveName != nil)
396 [
self _deregisterForAutosaveNotification];
398 _recentsAutosaveName = name;
400 if (_recentsAutosaveName != nil)
401 [
self _registerForAutosaveNotification];
406 - (CGRect)contentRectForBounds:(CGRect)bounds
412 + (double)_keyboardDelayForPartialSearchString:(
CPString)string
414 return (6 - MIN([
string length], 4)) / 10;
424 return [
super isOpaque] && [_cancelButton isOpaque] && [_searchButton isOpaque];
427 - (void)_updateCancelButtonVisibility
429 [_cancelButton setHidden:([[
self stringValue] length] === 0)];
434 if (![
self sendsWholeSearchString])
436 if ([
self sendsSearchStringImmediately])
437 [
self _sendPartialString];
440 [_partialStringTimer invalidate];
441 var timeInterval = [
CPSearchField _keyboardDelayForPartialSearchString:[
self stringValue]];
445 selector:@selector(_sendPartialString)
451 [
self _updateCancelButtonVisibility];
454 - (void)_sendAction:(
id)sender
456 [
self sendAction:[
self action] to:[
self target]];
459 - (void)sendAction:(
SEL)anAction to:(
id)anObject
463 [_partialStringTimer invalidate];
465 [
self _addStringToRecentSearches:[
self stringValue]];
466 [
self _updateCancelButtonVisibility];
469 - (void)_addStringToRecentSearches:(
CPString)string
471 if (
string === nil ||
string ===
@"" || [_recentSearches containsObject:
string])
475 [searches addObject:string];
476 [
self setRecentSearches:searches];
477 [
self _updateSearchMenu];
483 if (_CGRectContainsPoint([
self frame], aPoint))
489 - (BOOL)resignFirstResponder
499 if (_CGRectContainsPoint([
self searchButtonRectForBounds:[
self bounds]], point))
501 if (_searchMenuTemplate == nil)
503 if ([_searchButton target] && [_searchButton action])
504 [_searchButton mouseDown:anEvent];
506 [
self _sendAction:self];
511 else if (_CGRectContainsPoint([
self cancelButtonRectForBounds:[
self bounds]], point))
512 [_cancelButton mouseDown:anEvent];
558 [item setTag:CPSearchFieldRecentsTitleMenuItemTag];
559 [item setEnabled:NO];
560 [template addItem:item];
565 [item setTag:CPSearchFieldRecentsMenuItemTag];
566 [item setTarget:self];
567 [template addItem:item];
572 [item setTag:CPSearchFieldClearRecentsMenuItemTag];
573 [item setTarget:self];
574 [template addItem:item];
579 [item setTag:CPSearchFieldNoRecentsMenuItemTag];
580 [item setEnabled:NO];
581 [template addItem:item];
586 - (void)_updateSearchMenu
588 if (_searchMenuTemplate === nil)
592 countOfRecents = [_recentSearches count],
593 numberOfItems = [_searchMenuTemplate numberOfItems];
595 for (var i = 0; i < numberOfItems; i++)
597 var item = [[_searchMenuTemplate itemAtIndex:i] copy];
602 if (countOfRecents === 0)
605 if ([menu numberOfItems] > 0)
606 [
self _addSeparatorToMenu:menu];
611 var itemAction =
@selector(_searchFieldSearch:);
613 for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
619 [item setTarget:self];
620 [menu addItem:recentItem];
627 if (countOfRecents === 0)
630 if ([menu numberOfItems] > 0)
631 [
self _addSeparatorToMenu:menu];
633 [item setAction:@selector(_searchFieldClearRecents:)];
634 [item setTarget:self];
638 if (countOfRecents !== 0)
641 if ([menu numberOfItems] > 0)
642 [
self _addSeparatorToMenu:menu];
646 [item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
650 [menu setDelegate:self];
655 - (void)_addSeparatorToMenu:(
CPMenu)aMenu
658 [separator setEnabled:NO];
664 _canResignFirstResponder = NO;
669 _canResignFirstResponder = YES;
676 if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![
self isEnabled])
679 var aFrame = [[
self superview] convertRect:[
self frame] toView:nil],
680 location =
CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
684 [
self selectAll:nil];
688 - (void)_sendPartialString
690 [
super sendAction:[
self action] to:[
self target]];
691 [_partialStringTimer invalidate];
694 - (void)cancelOperation:(
id)sender
699 [
self _updateCancelButtonVisibility];
702 - (void)_searchFieldSearch:(
id)sender
704 var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
707 [
self _addStringToRecentSearches:searchString];
709 [
self setObjectValue:searchString];
710 [
self _sendPartialString];
711 [
self selectAll:nil];
713 [
self _updateCancelButtonVisibility];
716 - (void)_searchFieldClearRecents:(
id)sender
719 [
self _updateSearchMenu];
720 [
self setStringValue:@""];
721 [
self _updateCancelButtonVisibility];
724 - (void)_registerForAutosaveNotification
729 - (void)_deregisterForAutosaveNotification
734 - (void)_autosaveRecentSearchList
736 if (_recentsAutosaveName != nil)
740 - (void)_updateAutosavedRecents:(
id)notification
742 var name = [notification object];
746 - (void)_loadRecentSearchList
748 var name = [
self recentsAutosaveName];
755 _recentSearches = list;
770 [_searchButton removeFromSuperview];
771 [_cancelButton removeFromSuperview];
780 [coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
781 [coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
782 [coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
784 if (_recentsAutosaveName)
785 [coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
787 if (_searchMenuTemplate)
788 [coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
793 if (
self = [super initWithCoder:coder])
796 _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
797 _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
798 _maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
800 var
template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];