]> git.saurik.com Git - wxWidgets.git/blob - src/msw/textentry.cpp
fixing sdk compilo
[wxWidgets.git] / src / msw / textentry.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/textentry.cpp
3 // Purpose: wxTextEntry implementation for wxMSW
4 // Author: Vadim Zeitlin
5 // Created: 2007-09-26
6 // RCS-ID: $Id$
7 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/arrstr.h"
28 #include "wx/string.h"
29 #endif // WX_PRECOMP
30
31 #if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
32
33 #include "wx/textentry.h"
34 #include "wx/textcompleter.h"
35 #include "wx/dynlib.h"
36
37 #include <initguid.h>
38
39 #include "wx/msw/private.h"
40
41 #if wxUSE_UXTHEME
42 #include "wx/msw/uxtheme.h"
43 #endif
44
45 #define GetEditHwnd() ((HWND)(GetEditHWND()))
46
47 // ----------------------------------------------------------------------------
48 // Classes used by auto-completion implementation.
49 // ----------------------------------------------------------------------------
50
51 // standard VC6 SDK (WINVER == 0x0400) does not know about IAutoComplete
52 #if wxUSE_OLE && (WINVER >= 0x0500)
53 #define HAS_AUTOCOMPLETE
54 #endif
55
56 #ifdef HAS_AUTOCOMPLETE
57
58 #include "wx/msw/ole/oleutils.h"
59 #include <shldisp.h>
60
61 #if defined(__MINGW32__) || defined (__WATCOMC__) || defined(__CYGWIN__)
62 // needed for IID_IAutoComplete, IID_IAutoComplete2 and ACO_AUTOSUGGEST
63 #include <shlguid.h>
64
65 #ifndef ACO_AUTOAPPEND
66 #define ACO_AUTOAPPEND 0x02
67 #endif
68 #endif
69
70 #ifndef ACO_UPDOWNKEYDROPSLIST
71 #define ACO_UPDOWNKEYDROPSLIST 0x20
72 #endif
73
74 #ifndef SHACF_FILESYS_ONLY
75 #define SHACF_FILESYS_ONLY 0x00000010
76 #endif
77
78 #ifndef SHACF_FILESYS_DIRS
79 #define SHACF_FILESYS_DIRS 0x00000020
80 #endif
81
82 namespace
83 {
84
85 // Normally this interface and its IID are defined in shobjidl.h header file
86 // included in the platform SDK but MinGW and Cygwin don't have it so redefine
87 // the interface ourselves and, as long as we do it all, do it for all
88 // compilers to ensure we have the same behaviour for all of them and to avoid
89 // the need to check for concrete compilers and maybe even their versions.
90 class IAutoCompleteDropDown : public IUnknown
91 {
92 public:
93 virtual HRESULT wxSTDCALL GetDropDownStatus(DWORD *, LPWSTR *) = 0;
94 virtual HRESULT wxSTDCALL ResetEnumerator() = 0;
95 };
96
97 DEFINE_GUID(wxIID_IAutoCompleteDropDown,
98 0x3cd141f4, 0x3c6a, 0x11d2, 0xbc, 0xaa, 0x00, 0xc0, 0x4f, 0xd9, 0x29, 0xdb);
99
100 DEFINE_GUID(wxCLSID_AutoComplete,
101 0x00bb2763, 0x6a77, 0x11d0, 0xa5, 0x35, 0x00, 0xc0, 0x4f, 0xd7, 0xd0, 0x62);
102
103 // Small helper class which can be used to ensure thread safety even when
104 // wxUSE_THREADS==0 (and hence wxCriticalSection does nothing).
105 class CSLock
106 {
107 public:
108 CSLock(CRITICAL_SECTION& cs) : m_cs(&cs)
109 {
110 ::EnterCriticalSection(m_cs);
111 }
112
113 ~CSLock()
114 {
115 ::LeaveCriticalSection(m_cs);
116 }
117
118 private:
119 CRITICAL_SECTION * const m_cs;
120
121 wxDECLARE_NO_COPY_CLASS(CSLock);
122 };
123
124 } // anonymity namespace
125
126 // Implementation of string enumerator used by wxTextAutoCompleteData. This
127 // class simply forwards to wxTextCompleter associated with it.
128 //
129 // Notice that Next() method of this class is called by IAutoComplete
130 // background thread and so we must care about thread safety here.
131 class wxIEnumString : public IEnumString
132 {
133 public:
134 wxIEnumString()
135 {
136 Init();
137 }
138
139 void ChangeCompleter(wxTextCompleter *completer)
140 {
141 // Indicate to Next() that it should bail out as soon as possible.
142 {
143 CSLock lock(m_csRestart);
144
145 m_restart = TRUE;
146 }
147
148 // Now try to enter this critical section to ensure that Next() doesn't
149 // use the old pointer any more before changing it (this is vital as
150 // the old pointer will be destroyed after we return).
151 CSLock lock(m_csCompleter);
152
153 m_completer = completer;
154 }
155
156 void UpdatePrefix(const wxString& prefix)
157 {
158 CSLock lock(m_csRestart);
159
160 // We simply store the prefix here and will really update during the
161 // next call to our Next() method as we want to call Start() from the
162 // worker thread to prevent the main UI thread from blocking while the
163 // completions are generated.
164 m_prefix = prefix;
165 m_restart = TRUE;
166 }
167
168 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt,
169 LPOLESTR *rgelt,
170 ULONG *pceltFetched)
171 {
172 if ( !rgelt || (!pceltFetched && celt > 1) )
173 return E_POINTER;
174
175 ULONG pceltFetchedDummy;
176 if ( !pceltFetched )
177 pceltFetched = &pceltFetchedDummy;
178
179 *pceltFetched = 0;
180
181 CSLock lock(m_csCompleter);
182
183 if ( !RestartIfNeeded() )
184 return S_FALSE;
185
186 while ( celt-- )
187 {
188 // Stop iterating if we need to update completions anyhow.
189 if ( m_restart )
190 return S_FALSE;
191
192 const wxString s = m_completer->GetNext();
193 if ( s.empty() )
194 return S_FALSE;
195
196 const wxWX2WCbuf wcbuf = s.wc_str();
197 const size_t size = (wcslen(wcbuf) + 1)*sizeof(wchar_t);
198 void *olestr = CoTaskMemAlloc(size);
199 if ( !olestr )
200 return E_OUTOFMEMORY;
201
202 memcpy(olestr, wcbuf, size);
203
204 *rgelt++ = static_cast<LPOLESTR>(olestr);
205
206 ++(*pceltFetched);
207 }
208
209 return S_OK;
210 }
211
212 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
213 {
214 if ( !celt )
215 return E_INVALIDARG;
216
217 CSLock lock(m_csCompleter);
218
219 if ( !RestartIfNeeded() )
220 return S_FALSE;
221
222 while ( celt-- )
223 {
224 if ( m_restart )
225 return S_FALSE;
226
227 if ( m_completer->GetNext().empty() )
228 return S_FALSE;
229 }
230
231 return S_OK;
232 }
233
234 virtual HRESULT STDMETHODCALLTYPE Reset()
235 {
236 CSLock lock(m_csRestart);
237
238 m_restart = TRUE;
239
240 return S_OK;
241 }
242
243 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppEnum)
244 {
245 if ( !ppEnum )
246 return E_POINTER;
247
248 CSLock lock(m_csCompleter);
249
250 wxIEnumString * const e = new wxIEnumString;
251 e->AddRef();
252
253 e->ChangeCompleter(m_completer);
254
255 *ppEnum = e;
256
257 return S_OK;
258 }
259
260 DECLARE_IUNKNOWN_METHODS;
261
262 private:
263 // dtor doesn't have to be virtual as we're only ever deleted from our own
264 // Release() and are not meant to be derived form anyhow, but making it
265 // virtual silences gcc warnings; making it private makes it impossible to
266 // (mistakenly) delete us directly instead of calling Release()
267 virtual ~wxIEnumString()
268 {
269 ::DeleteCriticalSection(&m_csRestart);
270 ::DeleteCriticalSection(&m_csCompleter);
271 }
272
273 // Common part of all ctors.
274 void Init()
275 {
276 ::InitializeCriticalSection(&m_csCompleter);
277 ::InitializeCriticalSection(&m_csRestart);
278
279 m_completer = NULL;
280 m_restart = FALSE;
281 }
282
283 // Restart completions generation if needed. Should be only called from
284 // inside m_csCompleter.
285 //
286 // If false is returned, it means that there are no completions and that
287 // wxTextCompleter::GetNext() shouldn't be called at all.
288 bool RestartIfNeeded()
289 {
290 bool rc = true;
291 for ( ;; )
292 {
293 wxString prefix;
294 LONG restart;
295 {
296 CSLock lock(m_csRestart);
297
298 prefix = m_prefix;
299 restart = m_restart;
300
301 m_restart = FALSE;
302 } // Release m_csRestart before calling Start() to avoid blocking
303 // the main thread in UpdatePrefix() during its execution.
304
305 if ( !restart )
306 break;
307
308 rc = m_completer->Start(prefix);
309 }
310
311 return rc;
312 }
313
314
315 // Critical section protecting m_completer itself. It must be entered when
316 // using the pointer to ensure that we don't continue using a dangling one
317 // after it is destroyed.
318 CRITICAL_SECTION m_csCompleter;
319
320 // The completer we delegate to for the completions generation. It is never
321 // NULL after the initial ChangeCompleter() call.
322 wxTextCompleter *m_completer;
323
324
325 // Critical section m_prefix and m_restart. It should be only entered for
326 // short periods of time, i.e. we shouldn't call any wxTextCompleter
327 // methods from inside, to prevent the main thread from blocking on it in
328 // UpdatePrefix().
329 CRITICAL_SECTION m_csRestart;
330
331 // If m_restart is true, we need to call wxTextCompleter::Start() with the
332 // given prefix to restart generating the completions.
333 wxString m_prefix;
334
335 // Notice that we use LONG and not bool here to ensure that reading this
336 // value is atomic (32 bit reads are atomic operations under all Windows
337 // versions but reading bool isn't necessarily).
338 LONG m_restart;
339
340
341 wxDECLARE_NO_COPY_CLASS(wxIEnumString);
342 };
343
344 BEGIN_IID_TABLE(wxIEnumString)
345 ADD_IID(Unknown)
346 ADD_IID(EnumString)
347 END_IID_TABLE;
348
349 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
350
351
352 // This class gathers the all auto-complete-related stuff we use. It is
353 // allocated on demand by wxTextEntry when AutoComplete() is called.
354 class wxTextAutoCompleteData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
355 {
356 public:
357 // The constructor associates us with the given text entry.
358 wxTextAutoCompleteData(wxTextEntry *entry)
359 : m_entry(entry),
360 m_win(entry->GetEditableWindow())
361 {
362 m_autoComplete = NULL;
363 m_autoCompleteDropDown = NULL;
364 m_enumStrings = NULL;
365
366 m_fixedCompleter = NULL;
367 m_customCompleter = NULL;
368
369 m_connectedCharEvent = false;
370
371 // Create an object exposing IAutoComplete interface which we'll later
372 // use to get IAutoComplete2 as the latter can't be created directly,
373 // apparently.
374 HRESULT hr = CoCreateInstance
375 (
376 wxCLSID_AutoComplete,
377 NULL,
378 CLSCTX_INPROC_SERVER,
379 IID_IAutoComplete,
380 reinterpret_cast<void **>(&m_autoComplete)
381 );
382 if ( FAILED(hr) )
383 {
384 wxLogApiError(wxT("CoCreateInstance(CLSID_AutoComplete)"), hr);
385 return;
386 }
387
388 // Create a string enumerator and initialize the completer with it.
389 m_enumStrings = new wxIEnumString;
390 m_enumStrings->AddRef();
391 hr = m_autoComplete->Init(m_entry->GetEditHWND(), m_enumStrings,
392 NULL, NULL);
393 if ( FAILED(hr) )
394 {
395 wxLogApiError(wxT("IAutoComplete::Init"), hr);
396
397 m_enumStrings->Release();
398 m_enumStrings = NULL;
399
400 return;
401 }
402
403 // As explained in DoRefresh(), we need to call IAutoCompleteDropDown::
404 // ResetEnumerator() if we want to be able to change the completions on
405 // the fly. In principle we could live without it, i.e. return true
406 // from IsOk() even if this QueryInterface() fails, but it doesn't look
407 // like this is ever going to have in practice anyhow as the shell-
408 // provided IAutoComplete always implements IAutoCompleteDropDown too.
409 hr = m_autoComplete->QueryInterface
410 (
411 wxIID_IAutoCompleteDropDown,
412 reinterpret_cast<void **>(&m_autoCompleteDropDown)
413 );
414 if ( FAILED(hr) )
415 {
416 wxLogApiError(wxT("IAutoComplete::QI(IAutoCompleteDropDown)"), hr);
417 return;
418 }
419
420 // Finally set the completion options using IAutoComplete2.
421 IAutoComplete2 *pAutoComplete2 = NULL;
422 hr = m_autoComplete->QueryInterface
423 (
424 IID_IAutoComplete2,
425 reinterpret_cast<void **>(&pAutoComplete2)
426 );
427 if ( SUCCEEDED(hr) )
428 {
429 pAutoComplete2->SetOptions(ACO_AUTOSUGGEST |
430 ACO_AUTOAPPEND |
431 ACO_UPDOWNKEYDROPSLIST);
432 pAutoComplete2->Release();
433 }
434 }
435
436 ~wxTextAutoCompleteData()
437 {
438 delete m_customCompleter;
439 delete m_fixedCompleter;
440
441 if ( m_enumStrings )
442 m_enumStrings->Release();
443 if ( m_autoCompleteDropDown )
444 m_autoCompleteDropDown->Release();
445 if ( m_autoComplete )
446 m_autoComplete->Release();
447 }
448
449 // Must be called after creating this object to verify if initializing it
450 // succeeded.
451 bool IsOk() const
452 {
453 return m_autoComplete && m_autoCompleteDropDown && m_enumStrings;
454 }
455
456 void ChangeStrings(const wxArrayString& strings)
457 {
458 if ( !m_fixedCompleter )
459 m_fixedCompleter = new wxTextCompleterFixed;
460
461 m_fixedCompleter->SetCompletions(strings);
462
463 m_enumStrings->ChangeCompleter(m_fixedCompleter);
464
465 DoRefresh();
466 }
467
468 // Takes ownership of the pointer if it is non-NULL.
469 bool ChangeCustomCompleter(wxTextCompleter *completer)
470 {
471 // Ensure that the old completer is not used any more before deleting
472 // it.
473 m_enumStrings->ChangeCompleter(completer);
474
475 delete m_customCompleter;
476 m_customCompleter = completer;
477
478 if ( m_customCompleter )
479 {
480 // We postpone connecting to this event until we really need to do
481 // it (however we don't disconnect from it when we don't need it
482 // any more because we don't have wxUNBIND_OR_DISCONNECT_HACK...).
483 if ( !m_connectedCharEvent )
484 {
485 m_connectedCharEvent = true;
486
487 // Use the special wxEVT_AFTER_CHAR and not the usual
488 // wxEVT_CHAR here because we need to have the updated value of
489 // the text control in this handler in order to provide
490 // completions for the correct prefix and unfortunately we
491 // don't have any way to let DefWindowProc() run from our
492 // wxEVT_CHAR handler (as we must also let the other handlers
493 // defined at wx level run first).
494 //
495 // Notice that we can't use wxEVT_TEXT here
496 // neither as, due to our use of ACO_AUTOAPPEND, we get
497 // EN_CHANGE notifications from the control every time
498 // IAutoComplete auto-appends something to it.
499 wxBIND_OR_CONNECT_HACK(m_win, wxEVT_AFTER_CHAR,
500 wxKeyEventHandler,
501 wxTextAutoCompleteData::OnAfterChar,
502 this);
503 }
504
505 UpdateStringsFromCustomCompleter();
506 }
507
508 return true;
509 }
510
511 void DisableCompletion()
512 {
513 // We currently simply reset the list of possible strings as this seems
514 // to effectively disable auto-completion just fine. We could (and
515 // probably should) use IAutoComplete::Enable(FALSE) for this too but
516 // then we'd need to call Enable(TRUE) to turn it on back again later.
517 ChangeStrings(wxArrayString());
518 }
519
520 private:
521 // Must be called after changing the values to be returned by wxIEnumString
522 // to really make the changes stick.
523 void DoRefresh()
524 {
525 m_enumStrings->Reset();
526
527 // This is completely and utterly not documented and in fact the
528 // current MSDN seems to try to discourage us from using it by saying
529 // that "there is no reason to use this method unless the drop-down
530 // list is currently visible" but actually we absolutely must call it
531 // to force the auto-completer (and not just its drop-down!) to refresh
532 // the list of completions which could have changed now. Without this
533 // call the new choices returned by GetCompletions() that hadn't been
534 // returned by it before are simply silently ignored.
535 m_autoCompleteDropDown->ResetEnumerator();
536 }
537
538 // Update the strings returned by our string enumerator to correspond to
539 // the currently valid choices according to the custom completer.
540 void UpdateStringsFromCustomCompleter()
541 {
542 // As we use ACO_AUTOAPPEND, the selected part of the text is usually
543 // the one appended by us so don't consider it as part of the
544 // user-entered prefix.
545 long from, to;
546 m_entry->GetSelection(&from, &to);
547
548 if ( to == from )
549 from = m_entry->GetLastPosition(); // Take all if no selection.
550
551 const wxString prefix = m_entry->GetRange(0, from);
552
553 m_enumStrings->UpdatePrefix(prefix);
554
555 DoRefresh();
556 }
557
558 void OnAfterChar(wxKeyEvent& event)
559 {
560 // Notice that we must not refresh the completions when the user
561 // presses Backspace as this would result in adding back the just
562 // erased character(s) because of ACO_AUTOAPPEND option we use.
563 if ( m_customCompleter && event.GetKeyCode() != WXK_BACK )
564 UpdateStringsFromCustomCompleter();
565
566 event.Skip();
567 }
568
569
570 // The text entry we're associated with.
571 wxTextEntry * const m_entry;
572
573 // The window of this text entry.
574 wxWindow * const m_win;
575
576 // The auto-completer object itself.
577 IAutoComplete *m_autoComplete;
578
579 // Its IAutoCompleteDropDown interface needed for ResetEnumerator() call.
580 IAutoCompleteDropDown *m_autoCompleteDropDown;
581
582 // Enumerator for strings currently used for auto-completion.
583 wxIEnumString *m_enumStrings;
584
585 // Fixed string completer or NULL if none.
586 wxTextCompleterFixed *m_fixedCompleter;
587
588 // Custom completer or NULL if none.
589 wxTextCompleter *m_customCompleter;
590
591 // Initially false, set to true after connecting OnTextChanged() handler.
592 bool m_connectedCharEvent;
593
594
595 wxDECLARE_NO_COPY_CLASS(wxTextAutoCompleteData);
596 };
597
598 #endif // HAS_AUTOCOMPLETE
599
600 // ============================================================================
601 // wxTextEntry implementation
602 // ============================================================================
603
604 // ----------------------------------------------------------------------------
605 // initialization and destruction
606 // ----------------------------------------------------------------------------
607
608 wxTextEntry::wxTextEntry()
609 {
610 #ifdef HAS_AUTOCOMPLETE
611 m_autoCompleteData = NULL;
612 #endif // HAS_AUTOCOMPLETE
613 }
614
615 wxTextEntry::~wxTextEntry()
616 {
617 #ifdef HAS_AUTOCOMPLETE
618 delete m_autoCompleteData;
619 #endif // HAS_AUTOCOMPLETE
620 }
621
622 // ----------------------------------------------------------------------------
623 // operations on text
624 // ----------------------------------------------------------------------------
625
626 void wxTextEntry::WriteText(const wxString& text)
627 {
628 ::SendMessage(GetEditHwnd(), EM_REPLACESEL, 0, wxMSW_CONV_LPARAM(text));
629 }
630
631 wxString wxTextEntry::DoGetValue() const
632 {
633 return wxGetWindowText(GetEditHWND());
634 }
635
636 void wxTextEntry::Remove(long from, long to)
637 {
638 DoSetSelection(from, to, SetSel_NoScroll);
639 WriteText(wxString());
640 }
641
642 // ----------------------------------------------------------------------------
643 // clipboard operations
644 // ----------------------------------------------------------------------------
645
646 void wxTextEntry::Copy()
647 {
648 ::SendMessage(GetEditHwnd(), WM_COPY, 0, 0);
649 }
650
651 void wxTextEntry::Cut()
652 {
653 ::SendMessage(GetEditHwnd(), WM_CUT, 0, 0);
654 }
655
656 void wxTextEntry::Paste()
657 {
658 ::SendMessage(GetEditHwnd(), WM_PASTE, 0, 0);
659 }
660
661 // ----------------------------------------------------------------------------
662 // undo/redo
663 // ----------------------------------------------------------------------------
664
665 void wxTextEntry::Undo()
666 {
667 ::SendMessage(GetEditHwnd(), EM_UNDO, 0, 0);
668 }
669
670 void wxTextEntry::Redo()
671 {
672 // same as Undo, since Undo undoes the undo
673 Undo();
674 return;
675 }
676
677 bool wxTextEntry::CanUndo() const
678 {
679 return ::SendMessage(GetEditHwnd(), EM_CANUNDO, 0, 0) != 0;
680 }
681
682 bool wxTextEntry::CanRedo() const
683 {
684 // see comment in Redo()
685 return CanUndo();
686 }
687
688 // ----------------------------------------------------------------------------
689 // insertion point and selection
690 // ----------------------------------------------------------------------------
691
692 void wxTextEntry::SetInsertionPoint(long pos)
693 {
694 // calling DoSetSelection(-1, -1) would select everything which is not what
695 // we want here
696 if ( pos == -1 )
697 pos = GetLastPosition();
698
699 // be careful to call DoSetSelection() which is overridden in wxTextCtrl
700 // and not just SetSelection() here
701 DoSetSelection(pos, pos);
702 }
703
704 long wxTextEntry::GetInsertionPoint() const
705 {
706 long from;
707 GetSelection(&from, NULL);
708 return from;
709 }
710
711 long wxTextEntry::GetLastPosition() const
712 {
713 return ::SendMessage(GetEditHwnd(), EM_LINELENGTH, 0, 0);
714 }
715
716 void wxTextEntry::DoSetSelection(long from, long to, int WXUNUSED(flags))
717 {
718 // if from and to are both -1, it means (in wxWidgets) that all text should
719 // be selected, translate this into Windows convention
720 if ( (from == -1) && (to == -1) )
721 {
722 from = 0;
723 }
724
725 ::SendMessage(GetEditHwnd(), EM_SETSEL, from, to);
726 }
727
728 void wxTextEntry::GetSelection(long *from, long *to) const
729 {
730 DWORD dwStart, dwEnd;
731 ::SendMessage(GetEditHwnd(), EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
732
733 if ( from )
734 *from = dwStart;
735 if ( to )
736 *to = dwEnd;
737 }
738
739 // ----------------------------------------------------------------------------
740 // auto-completion
741 // ----------------------------------------------------------------------------
742
743 #if wxUSE_OLE
744
745 #ifdef HAS_AUTOCOMPLETE
746
747 #if wxUSE_DYNLIB_CLASS
748
749 bool wxTextEntry::DoAutoCompleteFileNames(int flags)
750 {
751 typedef HRESULT (WINAPI *SHAutoComplete_t)(HWND, DWORD);
752 static SHAutoComplete_t s_pfnSHAutoComplete = (SHAutoComplete_t)-1;
753 static wxDynamicLibrary s_dllShlwapi;
754 if ( s_pfnSHAutoComplete == (SHAutoComplete_t)-1 )
755 {
756 if ( !s_dllShlwapi.Load(wxT("shlwapi.dll"), wxDL_VERBATIM | wxDL_QUIET) )
757 {
758 s_pfnSHAutoComplete = NULL;
759 }
760 else
761 {
762 wxDL_INIT_FUNC(s_pfn, SHAutoComplete, s_dllShlwapi);
763 }
764 }
765
766 if ( !s_pfnSHAutoComplete )
767 return false;
768
769 DWORD dwFlags = 0;
770 if ( flags & wxFILE )
771 dwFlags |= SHACF_FILESYS_ONLY;
772 else if ( flags & wxDIR )
773 dwFlags |= SHACF_FILESYS_DIRS;
774 else
775 {
776 wxFAIL_MSG(wxS("No flags for file name auto completion?"));
777 return false;
778 }
779
780 HRESULT hr = (*s_pfnSHAutoComplete)(GetEditHwnd(), dwFlags);
781 if ( FAILED(hr) )
782 {
783 wxLogApiError(wxT("SHAutoComplete()"), hr);
784
785 return false;
786 }
787
788 // Disable the other kinds of completion now that we use the built-in file
789 // names completion.
790 if ( m_autoCompleteData )
791 m_autoCompleteData->DisableCompletion();
792
793 return true;
794 }
795
796 #endif // wxUSE_DYNLIB_CLASS
797
798 wxTextAutoCompleteData *wxTextEntry::GetOrCreateCompleter()
799 {
800 if ( !m_autoCompleteData )
801 {
802 wxTextAutoCompleteData * const ac = new wxTextAutoCompleteData(this);
803 if ( ac->IsOk() )
804 m_autoCompleteData = ac;
805 else
806 delete ac;
807 }
808
809 return m_autoCompleteData;
810 }
811
812 bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
813 {
814 wxTextAutoCompleteData * const ac = GetOrCreateCompleter();
815 if ( !ac )
816 return false;
817
818 ac->ChangeStrings(choices);
819
820 return true;
821 }
822
823 bool wxTextEntry::DoAutoCompleteCustom(wxTextCompleter *completer)
824 {
825 // First deal with the case when we just want to disable auto-completion.
826 if ( !completer )
827 {
828 if ( m_autoCompleteData )
829 m_autoCompleteData->DisableCompletion();
830 //else: Nothing to do, we hadn't used auto-completion even before.
831 }
832 else // Have a valid completer.
833 {
834 wxTextAutoCompleteData * const ac = GetOrCreateCompleter();
835 if ( !ac )
836 {
837 // Delete the custom completer for consistency with the case when
838 // we succeed to avoid memory leaks in user code.
839 delete completer;
840 return false;
841 }
842
843 // This gives ownership of the custom completer to m_autoCompleteData.
844 if ( !ac->ChangeCustomCompleter(completer) )
845 return false;
846 }
847
848 return true;
849 }
850
851 #else // !HAS_AUTOCOMPLETE
852
853 // We still need to define stubs as we declared these overrides in the header.
854
855 bool wxTextEntry::DoAutoCompleteFileNames(int flags)
856 {
857 return wxTextEntryBase::DoAutoCompleteFileNames(flags);
858 }
859
860 bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
861 {
862 return wxTextEntryBase::DoAutoCompleteStrings(choices);
863 }
864
865 bool wxTextEntry::DoAutoCompleteCustom(wxTextCompleter *completer)
866 {
867 return wxTextEntryBase::DoAutoCompleteCustom(completer);
868 }
869
870 #endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
871
872 #endif // wxUSE_OLE
873
874 // ----------------------------------------------------------------------------
875 // editable state
876 // ----------------------------------------------------------------------------
877
878 bool wxTextEntry::IsEditable() const
879 {
880 return !(::GetWindowLong(GetEditHwnd(), GWL_STYLE) & ES_READONLY);
881 }
882
883 void wxTextEntry::SetEditable(bool editable)
884 {
885 ::SendMessage(GetEditHwnd(), EM_SETREADONLY, !editable, 0);
886 }
887
888 // ----------------------------------------------------------------------------
889 // max length
890 // ----------------------------------------------------------------------------
891
892 void wxTextEntry::SetMaxLength(unsigned long len)
893 {
894 if ( len >= 0xffff )
895 {
896 // this will set it to a platform-dependent maximum (much more
897 // than 64Kb under NT)
898 len = 0;
899 }
900
901 ::SendMessage(GetEditHwnd(), EM_LIMITTEXT, len, 0);
902 }
903
904 // ----------------------------------------------------------------------------
905 // hints
906 // ----------------------------------------------------------------------------
907
908 #if wxUSE_UXTHEME
909
910 #ifndef EM_SETCUEBANNER
911 #define EM_SETCUEBANNER 0x1501
912 #define EM_GETCUEBANNER 0x1502
913 #endif
914
915 bool wxTextEntry::SetHint(const wxString& hint)
916 {
917 if ( wxUxThemeEngine::GetIfActive() )
918 {
919 // notice that this message always works with Unicode strings
920 //
921 // we always use TRUE for wParam to show the hint even when the window
922 // has focus, otherwise there would be no way to show the hint for the
923 // initially focused window
924 if ( ::SendMessage(GetEditHwnd(), EM_SETCUEBANNER,
925 TRUE, (LPARAM)(const wchar_t *)hint.wc_str()) )
926 return true;
927 }
928
929 return wxTextEntryBase::SetHint(hint);
930 }
931
932 wxString wxTextEntry::GetHint() const
933 {
934 if ( wxUxThemeEngine::GetIfActive() )
935 {
936 wchar_t buf[256];
937 if ( ::SendMessage(GetEditHwnd(), EM_GETCUEBANNER,
938 (WPARAM)buf, WXSIZEOF(buf)) )
939 return wxString(buf);
940 }
941
942 return wxTextEntryBase::GetHint();
943 }
944
945
946 #endif // wxUSE_UXTHEME
947
948 // ----------------------------------------------------------------------------
949 // margins support
950 // ----------------------------------------------------------------------------
951
952 bool wxTextEntry::DoSetMargins(const wxPoint& margins)
953 {
954 #if !defined(__WXWINCE__)
955 bool res = true;
956
957 if ( margins.x != -1 )
958 {
959 // Set both horizontal margins to the given value, we don't distinguish
960 // between left and right margin at wx API level and it seems to be
961 // better to change both of them than only left one.
962 ::SendMessage(GetEditHwnd(), EM_SETMARGINS,
963 EC_LEFTMARGIN | EC_RIGHTMARGIN,
964 MAKELONG(margins.x, margins.x));
965 }
966
967 if ( margins.y != -1 )
968 {
969 res = false;
970 }
971
972 return res;
973 #else
974 return false;
975 #endif
976 }
977
978 wxPoint wxTextEntry::DoGetMargins() const
979 {
980 #if !defined(__WXWINCE__)
981 LRESULT lResult = ::SendMessage(GetEditHwnd(), EM_GETMARGINS,
982 0, 0);
983 int left = LOWORD(lResult);
984 int top = -1;
985 return wxPoint(left, top);
986 #else
987 return wxPoint(-1, -1);
988 #endif
989 }
990
991 #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX