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