]> git.saurik.com Git - wxWidgets.git/blob - src/msw/textentry.cpp
fix a hang up in wxExecute(wxArrayString& output) overload (#4380)
[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/dynlib.h"
35
36 #include "wx/msw/private.h"
37
38 #define GetEditHwnd() ((HWND)(GetEditHWND()))
39
40 // ----------------------------------------------------------------------------
41 // wxIEnumString implements IEnumString interface
42 // ----------------------------------------------------------------------------
43
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
50
51 #include "wx/msw/ole/oleutils.h"
52 #include <shldisp.h>
53
54 #if defined(__MINGW32__) || defined (__WATCOMC__)
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
67 DEFINE_GUID(CLSID_AutoComplete,
68 0x00bb2763, 0x6a77, 0x11d0, 0xa5, 0x35, 0x00, 0xc0, 0x4f, 0xd7, 0xd0, 0x62);
69
70 class wxIEnumString : public IEnumString
71 {
72 public:
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
98 const wxWX2WCbuf wcbuf = m_strings[m_index].wc_str();
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
147 private:
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
155 const wxArrayString m_strings;
156 unsigned m_index;
157
158 DECLARE_NO_COPY_CLASS(wxIEnumString)
159 };
160
161 BEGIN_IID_TABLE(wxIEnumString)
162 ADD_IID(Unknown)
163 ADD_IID(EnumString)
164 END_IID_TABLE;
165
166 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
167
168 #endif // HAS_AUTOCOMPLETE
169
170 // ============================================================================
171 // wxTextEntry implementation
172 // ============================================================================
173
174 // ----------------------------------------------------------------------------
175 // operations on text
176 // ----------------------------------------------------------------------------
177
178 void wxTextEntry::WriteText(const wxString& text)
179 {
180 ::SendMessage(GetEditHwnd(), EM_REPLACESEL, 0, (LPARAM)text.wx_str());
181 }
182
183 wxString wxTextEntry::GetValue() const
184 {
185 return wxGetWindowText(GetEditHWND());
186 }
187
188 void wxTextEntry::Remove(long from, long to)
189 {
190 DoSetSelection(from, to, SetSel_NoScroll);
191 WriteText(wxString());
192 }
193
194 // ----------------------------------------------------------------------------
195 // clipboard operations
196 // ----------------------------------------------------------------------------
197
198 void wxTextEntry::Copy()
199 {
200 ::SendMessage(GetEditHwnd(), WM_COPY, 0, 0);
201 }
202
203 void wxTextEntry::Cut()
204 {
205 ::SendMessage(GetEditHwnd(), WM_CUT, 0, 0);
206 }
207
208 void wxTextEntry::Paste()
209 {
210 ::SendMessage(GetEditHwnd(), WM_PASTE, 0, 0);
211 }
212
213 // ----------------------------------------------------------------------------
214 // undo/redo
215 // ----------------------------------------------------------------------------
216
217 void wxTextEntry::Undo()
218 {
219 ::SendMessage(GetEditHwnd(), EM_UNDO, 0, 0);
220 }
221
222 void wxTextEntry::Redo()
223 {
224 // same as Undo, since Undo undoes the undo
225 Undo();
226 return;
227 }
228
229 bool wxTextEntry::CanUndo() const
230 {
231 return ::SendMessage(GetEditHwnd(), EM_CANUNDO, 0, 0) != 0;
232 }
233
234 bool wxTextEntry::CanRedo() const
235 {
236 // see comment in Redo()
237 return CanUndo();
238 }
239
240 // ----------------------------------------------------------------------------
241 // insertion point and selection
242 // ----------------------------------------------------------------------------
243
244 void 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
251 long wxTextEntry::GetInsertionPoint() const
252 {
253 long from;
254 GetSelection(&from, NULL);
255 return from;
256 }
257
258 long wxTextEntry::GetLastPosition() const
259 {
260 return ::SendMessage(GetEditHwnd(), EM_LINELENGTH, 0, 0);
261 }
262
263 void 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
275 void 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
286 // ----------------------------------------------------------------------------
287 // auto-completion
288 // ----------------------------------------------------------------------------
289
290 bool wxTextEntry::AutoCompleteFileNames()
291 {
292 #ifdef HAS_AUTOCOMPLETE
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 if ( !s_dllShlwapi.Load(_T("shlwapi.dll"), wxDL_VERBATIM | wxDL_QUIET) )
299 {
300 s_pfnSHAutoComplete = NULL;
301 }
302 else
303 {
304 wxDL_INIT_FUNC(s_pfn, SHAutoComplete, s_dllShlwapi);
305 }
306 }
307
308 if ( !s_pfnSHAutoComplete )
309 return false;
310
311 HRESULT hr = (*s_pfnSHAutoComplete)(GetEditHwnd(), SHACF_FILESYS_ONLY);
312 if ( FAILED(hr) )
313 {
314 wxLogApiError(_T("SHAutoComplete()"), hr);
315
316 return false;
317 }
318 return true;
319 #else // !HAS_AUTOCOMPLETE
320 return false;
321 #endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
322 }
323
324 bool wxTextEntry::AutoComplete(const wxArrayString& choices)
325 {
326 #ifdef HAS_AUTOCOMPLETE
327 // create an object exposing IAutoComplete interface (don't go for
328 // IAutoComplete2 immediately as, presumably, it might be not available on
329 // older systems as otherwise why do we have both -- although in practice I
330 // don't know when can this happen)
331 IAutoComplete *pAutoComplete = NULL;
332 HRESULT hr = CoCreateInstance
333 (
334 CLSID_AutoComplete,
335 NULL,
336 CLSCTX_INPROC_SERVER,
337 IID_IAutoComplete,
338 wx_reinterpret_cast(void **, &pAutoComplete)
339 );
340 if ( FAILED(hr) )
341 {
342 wxLogApiError(_T("CoCreateInstance(CLSID_AutoComplete)"), hr);
343 return false;
344 }
345
346 // associate it with our strings
347 wxIEnumString *pEnumString = new wxIEnumString(choices);
348 pEnumString->AddRef();
349 hr = pAutoComplete->Init(GetEditHwnd(), pEnumString, NULL, NULL);
350 pEnumString->Release();
351 if ( FAILED(hr) )
352 {
353 wxLogApiError(_T("IAutoComplete::Init"), hr);
354 return false;
355 }
356
357 // if IAutoComplete2 is available, set more user-friendly options
358 IAutoComplete2 *pAutoComplete2 = NULL;
359 hr = pAutoComplete->QueryInterface
360 (
361 IID_IAutoComplete2,
362 wx_reinterpret_cast(void **, &pAutoComplete2)
363 );
364 if ( SUCCEEDED(hr) )
365 {
366 pAutoComplete2->SetOptions(ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST);
367 pAutoComplete2->Release();
368 }
369
370 // the docs are unclear about when can we release it but it seems safe to
371 // do it immediately, presumably the edit control itself keeps a reference
372 // to the auto completer object
373 pAutoComplete->Release();
374 return true;
375 #else // !HAS_AUTOCOMPLETE
376 wxUnusedVar(choices);
377
378 return false;
379 #endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
380 }
381
382 // ----------------------------------------------------------------------------
383 // editable state
384 // ----------------------------------------------------------------------------
385
386 bool wxTextEntry::IsEditable() const
387 {
388 return !(::GetWindowLong(GetEditHwnd(), GWL_STYLE) & ES_READONLY);
389 }
390
391 void wxTextEntry::SetEditable(bool editable)
392 {
393 ::SendMessage(GetEditHwnd(), EM_SETREADONLY, !editable, 0);
394 }
395
396 // ----------------------------------------------------------------------------
397 // max length
398 // ----------------------------------------------------------------------------
399
400 void 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 }
411
412 #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX