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