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