]> git.saurik.com Git - wxWidgets.git/blame - src/msw/textentry.cpp
handle NULL BSTRs as empty ones per Microsoft convention
[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"
59396417 34#include "wx/dynlib.h"
69a05ef6
VZ
35
36#include "wx/msw/private.h"
37
38#define GetEditHwnd() ((HWND)(GetEditHWND()))
39
0847dca6
VZ
40// ----------------------------------------------------------------------------
41// wxIEnumString implements IEnumString interface
42// ----------------------------------------------------------------------------
43
fd873451
VZ
44// standard VC6 SDK (WINVER == 0x0400) does not know about IAutoComplete
45#if wxUSE_OLE && (WINVER >= 0x0500)
46 #define HAS_AUTOCOMPLETE
47#endif
48
49#ifdef HAS_AUTOCOMPLETE
0847dca6
VZ
50
51#include "wx/msw/ole/oleutils.h"
52#include <shldisp.h>
53
96506d1d
VZ
54#if defined(__MINGW32__)
55 // needed for IID_IAutoComplete, IID_IAutoComplete2 and ACO_AUTOSUGGEST
56 #include <shlguid.h>
57#endif
58
59#ifndef ACO_UPDOWNKEYDROPSLIST
60 #define ACO_UPDOWNKEYDROPSLIST 0x20
61#endif
62
63#ifndef SHACF_FILESYS_ONLY
64 #define SHACF_FILESYS_ONLY 0x00000010
65#endif
66
0847dca6
VZ
67DEFINE_GUID(CLSID_AutoComplete,
68 0x00bb2763, 0x6a77, 0x11d0, 0xa5, 0x35, 0x00, 0xc0, 0x4f, 0xd7, 0xd0, 0x62);
69
70class wxIEnumString : public IEnumString
71{
72public:
73 wxIEnumString(const wxArrayString& strings) : m_strings(strings)
74 {
75 m_index = 0;
76 }
77
78 DECLARE_IUNKNOWN_METHODS;
79
80 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt,
81 LPOLESTR *rgelt,
82 ULONG *pceltFetched)
83 {
84 if ( !rgelt || (!pceltFetched && celt > 1) )
85 return E_POINTER;
86
87 ULONG pceltFetchedDummy;
88 if ( !pceltFetched )
89 pceltFetched = &pceltFetchedDummy;
90
91 *pceltFetched = 0;
92
93 for ( const unsigned count = m_strings.size(); celt--; ++m_index )
94 {
95 if ( m_index == count )
96 return S_FALSE;
97
46eb9b54 98 const wxWX2WCbuf wcbuf = m_strings[m_index].wc_str();
0847dca6
VZ
99 const size_t size = (wcslen(wcbuf) + 1)*sizeof(wchar_t);
100 void *olestr = CoTaskMemAlloc(size);
101 if ( !olestr )
102 return E_OUTOFMEMORY;
103
104 memcpy(olestr, wcbuf, size);
105
106 *rgelt++ = wx_static_cast(LPOLESTR, olestr);
107
108 ++(*pceltFetched);
109 }
110
111 return S_OK;
112 }
113
114 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
115 {
116 m_index += celt;
117 if ( m_index > m_strings.size() )
118 {
119 m_index = m_strings.size();
120 return S_FALSE;
121 }
122
123 return S_OK;
124 }
125
126 virtual HRESULT STDMETHODCALLTYPE Reset()
127 {
128 m_index = 0;
129
130 return S_OK;
131 }
132
133 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppEnum)
134 {
135 if ( !ppEnum )
136 return E_POINTER;
137
138 wxIEnumString *e = new wxIEnumString(m_strings);
139 e->m_index = m_index;
140
141 e->AddRef();
142 *ppEnum = e;
143
144 return S_OK;
145 }
146
147private:
3eeefdf9
VZ
148 // dtor doesn't have to be virtual as we're only ever deleted from our own
149 // Release() and are not meant to be derived form anyhow, but making it
150 // virtual silences gcc warnings; making it private makes it impossible to
151 // (mistakenly) delete us directly instead of calling Release()
152 virtual ~wxIEnumString() { }
153
154
0847dca6
VZ
155 const wxArrayString m_strings;
156 unsigned m_index;
157
158 DECLARE_NO_COPY_CLASS(wxIEnumString)
159};
160
161BEGIN_IID_TABLE(wxIEnumString)
162 ADD_IID(Unknown)
163 ADD_IID(EnumString)
164END_IID_TABLE;
165
166IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
167
fd873451 168#endif // HAS_AUTOCOMPLETE
0847dca6 169
69a05ef6
VZ
170// ============================================================================
171// wxTextEntry implementation
172// ============================================================================
173
0847dca6
VZ
174// ----------------------------------------------------------------------------
175// operations on text
176// ----------------------------------------------------------------------------
177
69a05ef6
VZ
178void wxTextEntry::WriteText(const wxString& text)
179{
180 ::SendMessage(GetEditHwnd(), EM_REPLACESEL, 0, (LPARAM)text.wx_str());
181}
182
183wxString wxTextEntry::GetValue() const
184{
185 return wxGetWindowText(GetEditHWND());
186}
187
188void wxTextEntry::Remove(long from, long to)
189{
190 DoSetSelection(from, to, SetSel_NoScroll);
191 WriteText(wxString());
192}
193
0847dca6
VZ
194// ----------------------------------------------------------------------------
195// clipboard operations
196// ----------------------------------------------------------------------------
197
69a05ef6
VZ
198void wxTextEntry::Copy()
199{
200 ::SendMessage(GetEditHwnd(), WM_COPY, 0, 0);
201}
202
203void wxTextEntry::Cut()
204{
205 ::SendMessage(GetEditHwnd(), WM_CUT, 0, 0);
206}
207
208void wxTextEntry::Paste()
209{
210 ::SendMessage(GetEditHwnd(), WM_PASTE, 0, 0);
211}
212
0847dca6
VZ
213// ----------------------------------------------------------------------------
214// undo/redo
215// ----------------------------------------------------------------------------
216
69a05ef6
VZ
217void wxTextEntry::Undo()
218{
219 ::SendMessage(GetEditHwnd(), EM_UNDO, 0, 0);
220}
221
222void wxTextEntry::Redo()
223{
3cb6eaec 224 // same as Undo, since Undo undoes the undo
69a05ef6
VZ
225 Undo();
226 return;
227}
228
229bool wxTextEntry::CanUndo() const
230{
231 return ::SendMessage(GetEditHwnd(), EM_CANUNDO, 0, 0) != 0;
232}
233
234bool wxTextEntry::CanRedo() const
235{
236 // see comment in Redo()
237 return CanUndo();
238}
239
0847dca6
VZ
240// ----------------------------------------------------------------------------
241// insertion point and selection
242// ----------------------------------------------------------------------------
243
69a05ef6
VZ
244void wxTextEntry::SetInsertionPoint(long pos)
245{
246 // be careful to call DoSetSelection() which is overridden in wxTextCtrl
247 // and not just SetSelection() here
248 DoSetSelection(pos, pos);
249}
250
251long wxTextEntry::GetInsertionPoint() const
252{
253 long from;
254 GetSelection(&from, NULL);
255 return from;
256}
257
258long wxTextEntry::GetLastPosition() const
259{
260 return ::SendMessage(GetEditHwnd(), EM_LINELENGTH, 0, 0);
261}
262
263void wxTextEntry::DoSetSelection(long from, long to, int WXUNUSED(flags))
264{
265 // if from and to are both -1, it means (in wxWidgets) that all text should
266 // be selected, translate this into Windows convention
267 if ( (from == -1) && (to == -1) )
268 {
269 from = 0;
270 }
271
272 ::SendMessage(GetEditHwnd(), EM_SETSEL, from, to);
273}
274
275void wxTextEntry::GetSelection(long *from, long *to) const
276{
277 DWORD dwStart, dwEnd;
278 ::SendMessage(GetEditHwnd(), EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
279
280 if ( from )
281 *from = dwStart;
282 if ( to )
283 *to = dwEnd;
284}
285
0847dca6
VZ
286// ----------------------------------------------------------------------------
287// auto-completion
288// ----------------------------------------------------------------------------
289
59396417
VZ
290bool wxTextEntry::AutoCompleteFileNames()
291{
fd873451 292#ifdef HAS_AUTOCOMPLETE
59396417
VZ
293 typedef HRESULT (WINAPI *SHAutoComplete_t)(HWND, DWORD);
294 static SHAutoComplete_t s_pfnSHAutoComplete = (SHAutoComplete_t)-1;
295 static wxDynamicLibrary s_dllShlwapi;
296 if ( s_pfnSHAutoComplete == (SHAutoComplete_t)-1 )
297 {
298 wxLogNull noLog;
299
300 if ( !s_dllShlwapi.Load(_T("shlwapi.dll"), wxDL_VERBATIM) )
301 {
302 s_pfnSHAutoComplete = NULL;
303 }
304 else
305 {
306 wxDL_INIT_FUNC(s_pfn, SHAutoComplete, s_dllShlwapi);
307 }
308 }
309
310 if ( !s_pfnSHAutoComplete )
311 return false;
312
313 HRESULT hr = (*s_pfnSHAutoComplete)(GetEditHwnd(), SHACF_FILESYS_ONLY);
314 if ( FAILED(hr) )
315 {
316 wxLogApiError(_T("SHAutoComplete()"), hr);
317
318 return false;
319 }
59396417 320 return true;
fd873451
VZ
321#else // !HAS_AUTOCOMPLETE
322 return false;
323#endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
59396417
VZ
324}
325
0847dca6
VZ
326bool wxTextEntry::AutoComplete(const wxArrayString& choices)
327{
fd873451 328#ifdef HAS_AUTOCOMPLETE
0847dca6
VZ
329 // create an object exposing IAutoComplete interface (don't go for
330 // IAutoComplete2 immediately as, presumably, it might be not available on
331 // older systems as otherwise why do we have both -- although in practice I
332 // don't know when can this happen)
333 IAutoComplete *pAutoComplete = NULL;
334 HRESULT hr = CoCreateInstance
335 (
336 CLSID_AutoComplete,
337 NULL,
338 CLSCTX_INPROC_SERVER,
339 IID_IAutoComplete,
340 wx_reinterpret_cast(void **, &pAutoComplete)
341 );
342 if ( FAILED(hr) )
343 {
344 wxLogApiError(_T("CoCreateInstance(CLSID_AutoComplete)"), hr);
345 return false;
346 }
347
348 // associate it with our strings
349 wxIEnumString *pEnumString = new wxIEnumString(choices);
350 pEnumString->AddRef();
351 hr = pAutoComplete->Init(GetEditHwnd(), pEnumString, NULL, NULL);
352 pEnumString->Release();
353 if ( FAILED(hr) )
354 {
355 wxLogApiError(_T("IAutoComplete::Init"), hr);
356 return false;
357 }
358
359 // if IAutoComplete2 is available, set more user-friendly options
360 IAutoComplete2 *pAutoComplete2 = NULL;
361 hr = pAutoComplete->QueryInterface
362 (
363 IID_IAutoComplete2,
364 wx_reinterpret_cast(void **, &pAutoComplete2)
365 );
366 if ( SUCCEEDED(hr) )
367 {
368 pAutoComplete2->SetOptions(ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST);
369 pAutoComplete2->Release();
370 }
371
372 // the docs are unclear about when can we release it but it seems safe to
373 // do it immediately, presumably the edit control itself keeps a reference
374 // to the auto completer object
375 pAutoComplete->Release();
0847dca6 376 return true;
fd873451
VZ
377#else // !HAS_AUTOCOMPLETE
378 return false;
379#endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
0847dca6
VZ
380}
381
0847dca6
VZ
382// ----------------------------------------------------------------------------
383// editable state
384// ----------------------------------------------------------------------------
385
69a05ef6
VZ
386bool wxTextEntry::IsEditable() const
387{
5ad3f0c8 388 return !(::GetWindowLong(GetEditHwnd(), GWL_STYLE) & ES_READONLY);
69a05ef6
VZ
389}
390
391void wxTextEntry::SetEditable(bool editable)
392{
393 ::SendMessage(GetEditHwnd(), EM_SETREADONLY, !editable, 0);
394}
395
0847dca6
VZ
396// ----------------------------------------------------------------------------
397// max length
398// ----------------------------------------------------------------------------
399
69a05ef6
VZ
400void wxTextEntry::SetMaxLength(unsigned long len)
401{
402 if ( len >= 0xffff )
403 {
404 // this will set it to a platform-dependent maximum (much more
405 // than 64Kb under NT)
406 len = 0;
407 }
408
409 ::SendMessage(GetEditHwnd(), EM_LIMITTEXT, len, 0);
410}
96a4cdeb
VZ
411
412#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX