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