]> git.saurik.com Git - wxWidgets.git/blame - src/msw/textentry.cpp
Add some version checks to help compiling on OSX.
[wxWidgets.git] / src / msw / textentry.cpp
CommitLineData
69a05ef6
VZ
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
96506d1d 27 #include "wx/arrstr.h"
c0ae6c3b 28 #include "wx/string.h"
69a05ef6
VZ
29#endif // WX_PRECOMP
30
96a4cdeb
VZ
31#if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
32
69a05ef6 33#include "wx/textentry.h"
ea98f11c 34#include "wx/textcompleter.h"
59396417 35#include "wx/dynlib.h"
69a05ef6 36
b4f70f77
VS
37#include <initguid.h>
38
69a05ef6
VZ
39#include "wx/msw/private.h"
40
63f7d502
VZ
41#if wxUSE_UXTHEME
42 #include "wx/msw/uxtheme.h"
43#endif
44
69a05ef6
VZ
45#define GetEditHwnd() ((HWND)(GetEditHWND()))
46
0847dca6 47// ----------------------------------------------------------------------------
e71e4c93 48// Classes used by auto-completion implementation.
0847dca6
VZ
49// ----------------------------------------------------------------------------
50
fd873451
VZ
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
0847dca6
VZ
57
58#include "wx/msw/ole/oleutils.h"
59#include <shldisp.h>
60
715e4f7e 61#if defined(__MINGW32__) || defined (__WATCOMC__) || defined(__CYGWIN__)
96506d1d
VZ
62 // needed for IID_IAutoComplete, IID_IAutoComplete2 and ACO_AUTOSUGGEST
63 #include <shlguid.h>
0f0c5856
VZ
64
65 #ifndef ACO_AUTOAPPEND
66 #define ACO_AUTOAPPEND 0x02
67 #endif
96506d1d
VZ
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
e71e4c93
VZ
78namespace
79{
80
78f250a4
VZ
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.
86class IAutoCompleteDropDown : public IUnknown
87{
88public:
89 virtual HRESULT wxSTDCALL GetDropDownStatus(DWORD *, LPWSTR *) = 0;
90 virtual HRESULT wxSTDCALL ResetEnumerator() = 0;
91};
92
c6212697 93DEFINE_GUID(wxIID_IAutoCompleteDropDown,
78f250a4
VZ
94 0x3cd141f4, 0x3c6a, 0x11d2, 0xbc, 0xaa, 0x00, 0xc0, 0x4f, 0xd9, 0x29, 0xdb);
95
c6212697 96DEFINE_GUID(wxCLSID_AutoComplete,
78f250a4
VZ
97 0x00bb2763, 0x6a77, 0x11d0, 0xa5, 0x35, 0x00, 0xc0, 0x4f, 0xd7, 0xd0, 0x62);
98
e71e4c93
VZ
99// Small helper class which can be used to ensure thread safety even when
100// wxUSE_THREADS==0 (and hence wxCriticalSection does nothing).
101class CSLock
102{
103public:
104 CSLock(CRITICAL_SECTION& cs) : m_cs(&cs)
105 {
106 ::EnterCriticalSection(m_cs);
107 }
108
109 ~CSLock()
110 {
111 ::LeaveCriticalSection(m_cs);
112 }
113
114private:
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
85047589 123// class simply forwards to wxTextCompleter associated with it.
e71e4c93
VZ
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.
0847dca6
VZ
127class wxIEnumString : public IEnumString
128{
129public:
ea98f11c 130 wxIEnumString()
0847dca6 131 {
e71e4c93 132 Init();
0847dca6
VZ
133 }
134
85047589 135 void ChangeCompleter(wxTextCompleter *completer)
68e6eb7d 136 {
85047589
VZ
137 // Indicate to Next() that it should bail out as soon as possible.
138 {
139 CSLock lock(m_csRestart);
68e6eb7d 140
85047589
VZ
141 m_restart = TRUE;
142 }
e71e4c93 143
85047589
VZ
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;
e71e4c93
VZ
150 }
151
85047589 152 void UpdatePrefix(const wxString& prefix)
e71e4c93 153 {
85047589 154 CSLock lock(m_csRestart);
e71e4c93 155
85047589
VZ
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.
e71e4c93 160 m_prefix = prefix;
85047589 161 m_restart = TRUE;
e71e4c93 162 }
0847dca6
VZ
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
85047589 177 CSLock lock(m_csCompleter);
e71e4c93 178
85047589
VZ
179 if ( !RestartIfNeeded() )
180 return S_FALSE;
e71e4c93 181
85047589 182 while ( celt-- )
0847dca6 183 {
85047589
VZ
184 // Stop iterating if we need to update completions anyhow.
185 if ( m_restart )
0847dca6
VZ
186 return S_FALSE;
187
85047589
VZ
188 const wxString s = m_completer->GetNext();
189 if ( s.empty() )
190 return S_FALSE;
191
192 const wxWX2WCbuf wcbuf = s.wc_str();
0847dca6
VZ
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
5c33522f 200 *rgelt++ = static_cast<LPOLESTR>(olestr);
0847dca6
VZ
201
202 ++(*pceltFetched);
203 }
204
205 return S_OK;
206 }
207
208 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
209 {
85047589
VZ
210 if ( !celt )
211 return E_INVALIDARG;
e71e4c93 212
85047589
VZ
213 CSLock lock(m_csCompleter);
214
215 if ( !RestartIfNeeded() )
0847dca6 216 return S_FALSE;
85047589
VZ
217
218 while ( celt-- )
219 {
220 if ( m_restart )
221 return S_FALSE;
222
223 if ( m_completer->GetNext().empty() )
224 return S_FALSE;
0847dca6
VZ
225 }
226
227 return S_OK;
228 }
229
230 virtual HRESULT STDMETHODCALLTYPE Reset()
231 {
85047589 232 CSLock lock(m_csRestart);
e71e4c93 233
85047589 234 m_restart = TRUE;
0847dca6
VZ
235
236 return S_OK;
237 }
238
239 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppEnum)
240 {
241 if ( !ppEnum )
242 return E_POINTER;
243
85047589 244 CSLock lock(m_csCompleter);
0847dca6 245
85047589 246 wxIEnumString * const e = new wxIEnumString;
0847dca6 247 e->AddRef();
85047589
VZ
248
249 e->ChangeCompleter(m_completer);
250
0847dca6
VZ
251 *ppEnum = e;
252
253 return S_OK;
254 }
255
e71e4c93
VZ
256 DECLARE_IUNKNOWN_METHODS;
257
0847dca6 258private:
3eeefdf9
VZ
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()
e71e4c93
VZ
263 virtual ~wxIEnumString()
264 {
85047589
VZ
265 ::DeleteCriticalSection(&m_csRestart);
266 ::DeleteCriticalSection(&m_csCompleter);
e71e4c93
VZ
267 }
268
269 // Common part of all ctors.
270 void Init()
271 {
85047589
VZ
272 ::InitializeCriticalSection(&m_csCompleter);
273 ::InitializeCriticalSection(&m_csRestart);
e71e4c93
VZ
274
275 m_completer = NULL;
85047589 276 m_restart = FALSE;
e71e4c93
VZ
277 }
278
85047589
VZ
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()
e71e4c93 285 {
85047589
VZ
286 bool rc = true;
287 for ( ;; )
e71e4c93 288 {
85047589
VZ
289 wxString prefix;
290 LONG restart;
291 {
292 CSLock lock(m_csRestart);
3eeefdf9 293
85047589
VZ
294 prefix = m_prefix;
295 restart = m_restart;
e71e4c93 296
85047589
VZ
297 m_restart = FALSE;
298 } // Release m_csRestart before calling Start() to avoid blocking
299 // the main thread in UpdatePrefix() during its execution.
e71e4c93 300
85047589
VZ
301 if ( !restart )
302 break;
e71e4c93 303
85047589 304 rc = m_completer->Start(prefix);
e71e4c93 305 }
85047589
VZ
306
307 return rc;
e71e4c93
VZ
308 }
309
310
85047589
VZ
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;
e71e4c93 315
85047589
VZ
316 // The completer we delegate to for the completions generation. It is never
317 // NULL after the initial ChangeCompleter() call.
318 wxTextCompleter *m_completer;
0847dca6 319
e71e4c93 320
85047589
VZ
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.
e71e4c93
VZ
329 wxString m_prefix;
330
85047589
VZ
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
ea98f11c 336
85047589 337 wxDECLARE_NO_COPY_CLASS(wxIEnumString);
0847dca6
VZ
338};
339
340BEGIN_IID_TABLE(wxIEnumString)
341 ADD_IID(Unknown)
342 ADD_IID(EnumString)
343END_IID_TABLE;
344
345IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
346
ea98f11c 347
85047589
VZ
348// This class gathers the all auto-complete-related stuff we use. It is
349// allocated on demand by wxTextEntry when AutoComplete() is called.
ea98f11c
VZ
350class wxTextAutoCompleteData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
351{
352public:
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;
85047589
VZ
361
362 m_fixedCompleter = NULL;
ea98f11c
VZ
363 m_customCompleter = NULL;
364
b9a46ea5 365 m_connectedCharEvent = false;
ea98f11c
VZ
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 (
c6212697 372 wxCLSID_AutoComplete,
ea98f11c
VZ
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 (
c6212697 407 wxIID_IAutoCompleteDropDown,
ea98f11c
VZ
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 |
b9a46ea5 426 ACO_AUTOAPPEND |
ea98f11c
VZ
427 ACO_UPDOWNKEYDROPSLIST);
428 pAutoComplete2->Release();
429 }
430 }
431
432 ~wxTextAutoCompleteData()
433 {
434 delete m_customCompleter;
85047589 435 delete m_fixedCompleter;
ea98f11c
VZ
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 {
85047589
VZ
454 if ( !m_fixedCompleter )
455 m_fixedCompleter = new wxTextCompleterFixed;
456
457 m_fixedCompleter->SetCompletions(strings);
458
459 m_enumStrings->ChangeCompleter(m_fixedCompleter);
ea98f11c
VZ
460
461 DoRefresh();
462 }
463
464 // Takes ownership of the pointer if it is non-NULL.
465 bool ChangeCustomCompleter(wxTextCompleter *completer)
466 {
85047589
VZ
467 // Ensure that the old completer is not used any more before deleting
468 // it.
469 m_enumStrings->ChangeCompleter(completer);
470
ea98f11c
VZ
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...).
b9a46ea5 479 if ( !m_connectedCharEvent )
ea98f11c 480 {
b9a46ea5
VZ
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,
ea98f11c
VZ
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.
85047589 513 ChangeStrings(wxArrayString());
ea98f11c
VZ
514 }
515
516private:
85047589
VZ
517 // Must be called after changing the values to be returned by wxIEnumString
518 // to really make the changes stick.
ea98f11c
VZ
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 {
b9a46ea5
VZ
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
85047589 549 m_enumStrings->UpdatePrefix(prefix);
ea98f11c
VZ
550
551 DoRefresh();
552 }
553
b9a46ea5 554 void OnAfterChar(wxKeyEvent& event)
ea98f11c 555 {
b9a46ea5
VZ
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 )
ea98f11c
VZ
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
85047589
VZ
581 // Fixed string completer or NULL if none.
582 wxTextCompleterFixed *m_fixedCompleter;
583
ea98f11c
VZ
584 // Custom completer or NULL if none.
585 wxTextCompleter *m_customCompleter;
586
587 // Initially false, set to true after connecting OnTextChanged() handler.
b9a46ea5 588 bool m_connectedCharEvent;
ea98f11c
VZ
589
590
591 wxDECLARE_NO_COPY_CLASS(wxTextAutoCompleteData);
592};
593
fd873451 594#endif // HAS_AUTOCOMPLETE
0847dca6 595
69a05ef6
VZ
596// ============================================================================
597// wxTextEntry implementation
598// ============================================================================
599
ea98f11c
VZ
600// ----------------------------------------------------------------------------
601// initialization and destruction
602// ----------------------------------------------------------------------------
603
604wxTextEntry::wxTextEntry()
605{
606#ifdef HAS_AUTOCOMPLETE
607 m_autoCompleteData = NULL;
608#endif // HAS_AUTOCOMPLETE
609}
610
611wxTextEntry::~wxTextEntry()
612{
613#ifdef HAS_AUTOCOMPLETE
614 delete m_autoCompleteData;
615#endif // HAS_AUTOCOMPLETE
616}
617
0847dca6
VZ
618// ----------------------------------------------------------------------------
619// operations on text
620// ----------------------------------------------------------------------------
621
69a05ef6
VZ
622void wxTextEntry::WriteText(const wxString& text)
623{
624 ::SendMessage(GetEditHwnd(), EM_REPLACESEL, 0, (LPARAM)text.wx_str());
625}
626
135b23b2 627wxString wxTextEntry::DoGetValue() const
69a05ef6
VZ
628{
629 return wxGetWindowText(GetEditHWND());
630}
631
632void wxTextEntry::Remove(long from, long to)
633{
634 DoSetSelection(from, to, SetSel_NoScroll);
635 WriteText(wxString());
636}
637
0847dca6
VZ
638// ----------------------------------------------------------------------------
639// clipboard operations
640// ----------------------------------------------------------------------------
641
69a05ef6
VZ
642void wxTextEntry::Copy()
643{
644 ::SendMessage(GetEditHwnd(), WM_COPY, 0, 0);
645}
646
647void wxTextEntry::Cut()
648{
649 ::SendMessage(GetEditHwnd(), WM_CUT, 0, 0);
650}
651
652void wxTextEntry::Paste()
653{
654 ::SendMessage(GetEditHwnd(), WM_PASTE, 0, 0);
655}
656
0847dca6
VZ
657// ----------------------------------------------------------------------------
658// undo/redo
659// ----------------------------------------------------------------------------
660
69a05ef6
VZ
661void wxTextEntry::Undo()
662{
663 ::SendMessage(GetEditHwnd(), EM_UNDO, 0, 0);
664}
665
666void wxTextEntry::Redo()
667{
3cb6eaec 668 // same as Undo, since Undo undoes the undo
69a05ef6
VZ
669 Undo();
670 return;
671}
672
673bool wxTextEntry::CanUndo() const
674{
675 return ::SendMessage(GetEditHwnd(), EM_CANUNDO, 0, 0) != 0;
676}
677
678bool wxTextEntry::CanRedo() const
679{
680 // see comment in Redo()
681 return CanUndo();
682}
683
0847dca6
VZ
684// ----------------------------------------------------------------------------
685// insertion point and selection
686// ----------------------------------------------------------------------------
687
69a05ef6
VZ
688void wxTextEntry::SetInsertionPoint(long pos)
689{
2851cf25
VZ
690 // calling DoSetSelection(-1, -1) would select everything which is not what
691 // we want here
692 if ( pos == -1 )
693 pos = GetLastPosition();
694
69a05ef6
VZ
695 // be careful to call DoSetSelection() which is overridden in wxTextCtrl
696 // and not just SetSelection() here
697 DoSetSelection(pos, pos);
698}
699
700long wxTextEntry::GetInsertionPoint() const
701{
702 long from;
703 GetSelection(&from, NULL);
704 return from;
705}
706
707long wxTextEntry::GetLastPosition() const
708{
709 return ::SendMessage(GetEditHwnd(), EM_LINELENGTH, 0, 0);
710}
711
712void 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
724void 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
0847dca6
VZ
735// ----------------------------------------------------------------------------
736// auto-completion
737// ----------------------------------------------------------------------------
738
6502dc68 739#if wxUSE_OLE
6b30ffed
VZ
740
741#ifdef HAS_AUTOCOMPLETE
742
574479e8 743bool wxTextEntry::DoAutoCompleteFileNames()
59396417
VZ
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 {
9a83f860 750 if ( !s_dllShlwapi.Load(wxT("shlwapi.dll"), wxDL_VERBATIM | wxDL_QUIET) )
59396417
VZ
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 {
9a83f860 766 wxLogApiError(wxT("SHAutoComplete()"), hr);
59396417
VZ
767
768 return false;
769 }
ea98f11c
VZ
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
59396417
VZ
776 return true;
777}
778
ea98f11c 779wxTextAutoCompleteData *wxTextEntry::GetOrCreateCompleter()
0847dca6 780{
ea98f11c 781 if ( !m_autoCompleteData )
68e6eb7d 782 {
ea98f11c
VZ
783 wxTextAutoCompleteData * const ac = new wxTextAutoCompleteData(this);
784 if ( ac->IsOk() )
785 m_autoCompleteData = ac;
786 else
787 delete ac;
68e6eb7d
VZ
788 }
789
ea98f11c
VZ
790 return m_autoCompleteData;
791}
792
793bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
794{
795 wxTextAutoCompleteData * const ac = GetOrCreateCompleter();
796 if ( !ac )
0847dca6 797 return false;
0847dca6 798
ea98f11c
VZ
799 ac->ChangeStrings(choices);
800
801 return true;
802}
803
804bool wxTextEntry::DoAutoCompleteCustom(wxTextCompleter *completer)
805{
806 // First deal with the case when we just want to disable auto-completion.
807 if ( !completer )
0847dca6 808 {
ea98f11c
VZ
809 if ( m_autoCompleteData )
810 m_autoCompleteData->DisableCompletion();
811 //else: Nothing to do, we hadn't used auto-completion even before.
0847dca6 812 }
ea98f11c 813 else // Have a valid completer.
0847dca6 814 {
ea98f11c
VZ
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;
0847dca6
VZ
827 }
828
0847dca6 829 return true;
6b30ffed
VZ
830}
831
fd873451 832#else // !HAS_AUTOCOMPLETE
867b485e 833
6b30ffed
VZ
834// We still need to define stubs as we declared these overrides in the header.
835
836bool wxTextEntry::DoAutoCompleteFileNames()
837{
838 return wxTextEntryBase::DoAutoCompleteFileNames();
839}
840
841bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
842{
843 return wxTextEntryBase::DoAutoCompleteStrings(choices);
0847dca6 844}
6b30ffed 845
32bd17fc
VZ
846bool wxTextEntry::DoAutoCompleteCustom(wxTextCompleter *completer)
847{
8d43e8c6 848 return wxTextEntryBase::DoAutoCompleteCustom(completer);
32bd17fc
VZ
849}
850
6b30ffed
VZ
851#endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
852
6502dc68 853#endif // wxUSE_OLE
0847dca6 854
0847dca6
VZ
855// ----------------------------------------------------------------------------
856// editable state
857// ----------------------------------------------------------------------------
858
69a05ef6
VZ
859bool wxTextEntry::IsEditable() const
860{
5ad3f0c8 861 return !(::GetWindowLong(GetEditHwnd(), GWL_STYLE) & ES_READONLY);
69a05ef6
VZ
862}
863
864void wxTextEntry::SetEditable(bool editable)
865{
866 ::SendMessage(GetEditHwnd(), EM_SETREADONLY, !editable, 0);
867}
868
0847dca6
VZ
869// ----------------------------------------------------------------------------
870// max length
871// ----------------------------------------------------------------------------
872
69a05ef6
VZ
873void 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}
96a4cdeb 884
63f7d502
VZ
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
896bool wxTextEntry::SetHint(const wxString& hint)
897{
898 if ( wxUxThemeEngine::GetIfActive() )
899 {
900 // notice that this message always works with Unicode strings
7591b0bb
VZ
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
63f7d502 905 if ( ::SendMessage(GetEditHwnd(), EM_SETCUEBANNER,
7591b0bb 906 TRUE, (LPARAM)(const wchar_t *)hint.wc_str()) )
63f7d502
VZ
907 return true;
908 }
909
910 return wxTextEntryBase::SetHint(hint);
911}
912
913wxString 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)) )
d2f434e4 920 return wxString(buf);
63f7d502
VZ
921 }
922
923 return wxTextEntryBase::GetHint();
924}
925
926
927#endif // wxUSE_UXTHEME
928
0847e36e
JS
929// ----------------------------------------------------------------------------
930// margins support
931// ----------------------------------------------------------------------------
932
933bool 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
956wxPoint 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
96a4cdeb 969#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX