1///////////////////////////////////////////////////////////////////////////// 2// Name: src/cocoa/combobox.mm 3// Purpose: wxComboBox 4// Author: Ryan Norton 5// Modified by: 6// Created: 2005/02/16 7// Copyright: (c) 2003 David Elliott 8// Licence: wxWindows licence 9///////////////////////////////////////////////////////////////////////////// 10 11// 12// Impl notes: 13// There is no custom data source because doing so unnecessarily sacrifices 14// some native autocompletion behaviour (we would have to make our own - 15// the SimpleComboBox sample does so in the developer folder that 16// comes with OSX). One reason you might want this would be to have 17// only one array or be able to display numbers returned by an NSNumber 18// from the methods. 19// 20// One problem though is that wxCB_SORT isn't implemented... 21// 22// Also, not sure if it is correctly getting text field events since 23// I'm using SetNSComboBox instead of SetNSTextField 24// 25// doWxEvent is really hackish... but since there's only one event... 26// 27// Ideas for future improvement - other notes: 28// Combox w/o wxCB_DROPDOWN doesn't seem to be implementable 29//wxCB_READONLY Same as wxCB_DROPDOWN but only the strings specified as the combobox choices can be selected, it is impossible to select (even from a program) a string which is not in the choices list. 30//wxCB_SORT is possible with data source 31// 32// setIntercellSpacing:/setItemHeight: to autoadjust to number of inserted items? 33// 34/* 35 //example of autocompletion from SimpleComboBox Example 36 // ========================================================== 37// Combo box data source methods 38// ========================================================== 39 40- (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox { 41 return [genres count]; 42} 43- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index { 44 return [genres objectAtIndex:index]; 45} 46- (unsigned int)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string { 47 return [genres indexOfObject: string]; 48} 49 50- (NSString *) firstGenreMatchingPrefix:(NSString *)prefix { 51 NSString *string = nil; 52 NSString *lowercasePrefix = [prefix lowercaseString]; 53 NSEnumerator *stringEnum = [genres objectEnumerator]; 54 while ((string = [stringEnum nextObject])) { 55 if ([[string lowercaseString] hasPrefix: lowercasePrefix]) return string; 56 } 57 return nil; 58} 59 60- (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)inputString { 61 // This method is received after each character typed by the user, because we have checked the "completes" flag for genreComboBox in IB. 62 // Given the inputString the user has typed, see if we can find a genre with the prefix, and return it as the suggested complete string. 63 NSString *candidate = [self firstGenreMatchingPrefix: inputString]; 64 return (candidate ? candidate : inputString); 65} 66*/ 67 68// ============================================================================ 69// declarations 70// ============================================================================ 71 72// ---------------------------------------------------------------------------- 73// headers 74// ---------------------------------------------------------------------------- 75 76#include "wx/wxprec.h" 77 78#if wxUSE_COMBOBOX 79 80#include "wx/combobox.h" 81 82#include "wx/cocoa/objc/objc_uniquifying.h" 83 84#ifndef WX_PRECOMP 85 #include "wx/window.h" 86 #include "wx/log.h" 87 #include "wx/app.h" 88#endif // WX_PRECOMP 89 90#import <AppKit/NSComboBox.h> 91#import <Foundation/NSNotification.h> 92#import <Foundation/NSString.h> 93 94// ---------------------------------------------------------------------------- 95// globals 96// ---------------------------------------------------------------------------- 97WX_IMPLEMENT_OBJC_INTERFACE_HASHMAP(NSComboBox) 98 99void wxCocoaNSComboBox::AssociateNSComboBox(WX_NSComboBox cocoaNSComboBox) 100{ 101 if(cocoaNSComboBox) 102 { 103 sm_cocoaHash.insert(wxCocoaNSComboBoxHash::value_type(cocoaNSComboBox,this)); 104 105 [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxSelectionDidChangeNotification" object:cocoaNSComboBox]; 106 [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxSelectionIsChangingNotification" object:cocoaNSComboBox]; 107 [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxWillDismissNotification" object:cocoaNSComboBox]; 108 [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxWillPopUpNotification" object:cocoaNSComboBox]; 109 } 110} 111 112void wxCocoaNSComboBox::DisassociateNSComboBox(WX_NSComboBox cocoaNSComboBox) 113{ 114 if(cocoaNSComboBox) 115 { 116 sm_cocoaHash.erase(cocoaNSComboBox); 117 [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxSelectionDidChangeNotification" object:cocoaNSComboBox]; 118 [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxSelectionIsChangingNotification" object:cocoaNSComboBox]; 119 [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxWillDismissNotification" object:cocoaNSComboBox]; 120 [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxWillPopUpNotification" object:cocoaNSComboBox]; 121 } 122} 123 124// ============================================================================ 125// @class wxPoserNSComboBox 126// ============================================================================ 127@interface wxPoserNSComboBox : NSComboBox 128{ 129} 130 131- (void)comboBoxSelectionDidChange:(NSNotification *)notification; 132- (void)comboBoxSelectionIsChanging:(NSNotification *)notification; 133- (void)comboBoxWillDismiss:(NSNotification *)notification; 134- (void)comboBoxWillPopUp:(NSNotification *)notification; 135@end // wxPoserNSComboBox 136WX_DECLARE_GET_OBJC_CLASS(wxPoserNSComboBox,NSComboBox) 137 138//WX_IMPLEMENT_POSER(wxPoserNSComboBox); 139@implementation wxPoserNSComboBox : NSComboBox 140 141- (void)comboBoxSelectionDidChange:(NSNotification *)notification 142{ 143 wxCocoaNSComboBox *win = wxCocoaNSComboBox::GetFromCocoa(self); 144 win->doWxEvent(wxEVT_COMBOBOX); 145} 146 147- (void)comboBoxSelectionIsChanging:(NSNotification *)notification 148{ 149 //... 150} 151 152- (void)comboBoxWillDismiss:(NSNotification *)notification 153{ 154 //... 155} 156 157- (void)comboBoxWillPopUp:(NSNotification *)notification 158{ 159 //... 160} 161 162@end // implementation wxPoserNSComboBox 163WX_IMPLEMENT_GET_OBJC_CLASS(wxPoserNSComboBox,NSComboBox) 164 165#include "wx/cocoa/autorelease.h" 166#include "wx/cocoa/string.h" 167 168#import <AppKit/NSComboBox.h> 169 170BEGIN_EVENT_TABLE(wxComboBox, wxControl) 171END_EVENT_TABLE() 172WX_IMPLEMENT_COCOA_OWNER(wxComboBox,NSComboBox,NSTextField,NSView) 173WX_IMPLEMENT_COCOA_OWNER(wxComboBox,NSTextField,NSControl,NSView) 174 175bool wxComboBox::Create(wxWindow *parent, wxWindowID winid, 176 const wxString& value, 177 const wxPoint& pos, 178 const wxSize& size, 179 const wxArrayString& choices, 180 long style, 181 const wxValidator& validator, 182 const wxString& name) 183{ 184 wxCArrayString chs(choices); 185 186 return Create(parent, winid, value, pos, size, chs.GetCount(), 187 chs.GetStrings(), style, validator, name); 188} 189 190bool wxComboBox::Create(wxWindow *parent, wxWindowID winid, 191 const wxString& value, 192 const wxPoint& pos, 193 const wxSize& size, 194 int n, const wxString choices[], 195 long style, 196 const wxValidator& validator, 197 const wxString& name) 198{ 199 wxAutoNSAutoreleasePool pool; 200 if(!CreateControl(parent,winid,pos,size,style,validator,name)) 201 return false; 202 203 m_cocoaNSView = NULL; 204 SetNSComboBox([[WX_GET_OBJC_CLASS(wxPoserNSComboBox) alloc] initWithFrame:MakeDefaultNSRect(size)]); 205 [m_cocoaNSView release]; 206 [GetNSTextField() setStringValue:wxNSStringWithWxString(value.c_str())]; 207 [GetNSControl() sizeToFit]; 208 if(m_parent) 209 m_parent->CocoaAddChild(this); 210 SetInitialFrameRect(pos,size); 211 212 wxComboBox::Append(n, choices); 213 214 [GetNSComboBox() setCompletes:true]; //autocomplete :) 215 216 return true; 217} 218 219wxComboBox::~wxComboBox() 220{ 221 DisassociateNSComboBox(GetNSComboBox()); 222} 223 224void wxComboBox::doWxEvent(int nEvent) 225{ 226 wxCommandEvent event2(wxEVT_COMBOBOX, GetId() ); 227 event2.SetInt(GetSelection()); 228 event2.SetEventObject(this); 229 event2.SetString(GetStringSelection()); 230 HandleWindowEvent(event2); 231 232 // For consistency with MSW and GTK, also send a text updated event 233 // After all, the text is updated when a selection is made 234 wxCommandEvent TextEvent( wxEVT_TEXT, GetId() ); 235 TextEvent.SetString( GetStringSelection() ); 236 TextEvent.SetEventObject( this ); 237 HandleWindowEvent( TextEvent ); 238} 239 240 241void wxComboBox::SetSelection(int nSelection) 242{ 243 [GetNSComboBox() selectItemAtIndex:nSelection]; 244} 245 246wxString wxComboBox::GetStringSelection() 247{ 248 return wxStringWithNSString([GetNSComboBox() objectValueOfSelectedItem]); 249} 250 251void wxComboBox::DoClear() 252{ 253 [GetNSComboBox() removeAllItems]; 254 m_Datas.Clear(); 255} 256 257void wxComboBox::DoDeleteOneItem(unsigned int n) 258{ 259 [GetNSComboBox() removeItemAtIndex:n]; 260 m_Datas.RemoveAt(n); 261} 262 263unsigned int wxComboBox::GetCount() const 264{ 265 return (unsigned int)[GetNSComboBox() numberOfItems]; 266} 267 268wxString wxComboBox::GetString(unsigned int nIndex) const 269{ 270 return wxStringWithNSString([GetNSComboBox() itemObjectValueAtIndex:nIndex]); 271} 272 273void wxComboBox::SetString(unsigned int nIndex, const wxString& szString) 274{ 275 wxAutoNSAutoreleasePool pool; 276 //FIXME: There appears to be no "set item data" method - maybe 277 //an assignment would work? 278 [GetNSComboBox() removeItemAtIndex:nIndex]; 279 [GetNSComboBox() insertItemWithObjectValue:wxNSStringWithWxString(szString) atIndex:nIndex]; 280} 281 282int wxComboBox::FindString(const wxString& szItem, bool bCase) const 283{ 284 // FIXME: use wxItemContainerImmutable::FindString for bCase parameter 285 return [GetNSComboBox() indexOfItemWithObjectValue:wxNSStringWithWxString(szItem)]; 286} 287 288int wxComboBox::GetSelection() const 289{ 290 return [GetNSComboBox() indexOfSelectedItem]; 291} 292 293int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items, 294 unsigned int pos, 295 void **clientData, 296 wxClientDataType type) 297{ 298 wxAutoNSAutoreleasePool pool; 299 const unsigned int numITems = items.GetCount(); 300 for ( unsigned int i = 0; i < numITems; ++i, ++pos ) 301 { 302 [GetNSComboBox() insertItemWithObjectValue:wxNSStringWithWxString(items[i]) atIndex:(pos)]; 303 m_Datas.Insert(NULL, pos); 304 AssignNewItemClientData(pos, clientData, i, type); 305 } 306 return pos - 1; 307} 308 309void wxComboBox::DoSetItemClientData(unsigned int nIndex, void* pData) 310{ 311 m_Datas[nIndex] = pData; 312} 313 314void* wxComboBox::DoGetItemClientData(unsigned int nIndex) const 315{ 316 return m_Datas[nIndex]; 317} 318 319///////////////////////////////////////////////////////////////////////////// 320// wxTextEntry virtual implementations: 321 322void wxComboBox::WriteText(wxString const&) 323{ 324} 325 326wxString wxComboBox::GetValue() const 327{ 328 wxAutoNSAutoreleasePool pool; 329 return wxStringWithNSString([GetNSTextField() stringValue]); 330} 331 332void wxComboBox::Remove(long, long) 333{ 334} 335 336void wxComboBox::Cut() 337{ 338} 339 340void wxComboBox::Copy() 341{ 342} 343 344void wxComboBox::Paste() 345{ 346} 347 348void wxComboBox::Undo() 349{ 350} 351 352void wxComboBox::Redo() 353{ 354} 355 356bool wxComboBox::CanUndo() const 357{ 358 return false; 359} 360 361bool wxComboBox::CanRedo() const 362{ 363 return false; 364} 365 366void wxComboBox::SetInsertionPoint(long) 367{ 368} 369 370long wxComboBox::GetInsertionPoint() const 371{ 372 return 0; 373} 374 375wxTextPos wxComboBox::GetLastPosition() const 376{ 377 // working - returns the size of the wxString 378 return (long)(GetValue().Len()); 379} 380 381void wxComboBox::SetSelection(long, long) 382{ 383} 384 385void wxComboBox::GetSelection(long*, long*) const 386{ 387} 388 389bool wxComboBox::IsEditable() const 390{ 391 return [GetNSTextField() isEditable]; 392} 393 394void wxComboBox::SetEditable(bool editable) 395{ 396 // first ensure that the current value is stored (in case the user had not finished editing 397 // before SetEditable(FALSE) was called) 398 DoSetValue(GetValue(),1); 399 400 [GetNSTextField() setEditable: editable]; 401 402 // forces the focus on the textctrl to be lost - while focus is still maintained 403 // after SetEditable(FALSE) the user may still edit the control 404 // (might not the best way to do this..) 405 [GetNSTextField() abortEditing]; 406} 407 408#endif // wxUSE_COMBOBOX 409