]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/textentry.cpp
Store pointer to owning wxWindow in wxPizza widget
[wxWidgets.git] / src / msw / textentry.cpp
... / ...
CommitLineData
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
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
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++ = 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:
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
161BEGIN_IID_TABLE(wxIEnumString)
162 ADD_IID(Unknown)
163 ADD_IID(EnumString)
164END_IID_TABLE;
165
166IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
167
168#endif // HAS_AUTOCOMPLETE
169
170// ============================================================================
171// wxTextEntry implementation
172// ============================================================================
173
174// ----------------------------------------------------------------------------
175// operations on text
176// ----------------------------------------------------------------------------
177
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
194// ----------------------------------------------------------------------------
195// clipboard operations
196// ----------------------------------------------------------------------------
197
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
213// ----------------------------------------------------------------------------
214// undo/redo
215// ----------------------------------------------------------------------------
216
217void wxTextEntry::Undo()
218{
219 ::SendMessage(GetEditHwnd(), EM_UNDO, 0, 0);
220}
221
222void wxTextEntry::Redo()
223{
224 // same as Undo, since Undo undoes the undo
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
240// ----------------------------------------------------------------------------
241// insertion point and selection
242// ----------------------------------------------------------------------------
243
244void wxTextEntry::SetInsertionPoint(long pos)
245{
246 // calling DoSetSelection(-1, -1) would select everything which is not what
247 // we want here
248 if ( pos == -1 )
249 pos = GetLastPosition();
250
251 // be careful to call DoSetSelection() which is overridden in wxTextCtrl
252 // and not just SetSelection() here
253 DoSetSelection(pos, pos);
254}
255
256long wxTextEntry::GetInsertionPoint() const
257{
258 long from;
259 GetSelection(&from, NULL);
260 return from;
261}
262
263long wxTextEntry::GetLastPosition() const
264{
265 return ::SendMessage(GetEditHwnd(), EM_LINELENGTH, 0, 0);
266}
267
268void wxTextEntry::DoSetSelection(long from, long to, int WXUNUSED(flags))
269{
270 // if from and to are both -1, it means (in wxWidgets) that all text should
271 // be selected, translate this into Windows convention
272 if ( (from == -1) && (to == -1) )
273 {
274 from = 0;
275 }
276
277 ::SendMessage(GetEditHwnd(), EM_SETSEL, from, to);
278}
279
280void wxTextEntry::GetSelection(long *from, long *to) const
281{
282 DWORD dwStart, dwEnd;
283 ::SendMessage(GetEditHwnd(), EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
284
285 if ( from )
286 *from = dwStart;
287 if ( to )
288 *to = dwEnd;
289}
290
291// ----------------------------------------------------------------------------
292// auto-completion
293// ----------------------------------------------------------------------------
294
295#if wxUSE_OLE
296bool wxTextEntry::AutoCompleteFileNames()
297{
298#ifdef HAS_AUTOCOMPLETE
299 typedef HRESULT (WINAPI *SHAutoComplete_t)(HWND, DWORD);
300 static SHAutoComplete_t s_pfnSHAutoComplete = (SHAutoComplete_t)-1;
301 static wxDynamicLibrary s_dllShlwapi;
302 if ( s_pfnSHAutoComplete == (SHAutoComplete_t)-1 )
303 {
304 if ( !s_dllShlwapi.Load(_T("shlwapi.dll"), wxDL_VERBATIM | wxDL_QUIET) )
305 {
306 s_pfnSHAutoComplete = NULL;
307 }
308 else
309 {
310 wxDL_INIT_FUNC(s_pfn, SHAutoComplete, s_dllShlwapi);
311 }
312 }
313
314 if ( !s_pfnSHAutoComplete )
315 return false;
316
317 HRESULT hr = (*s_pfnSHAutoComplete)(GetEditHwnd(), SHACF_FILESYS_ONLY);
318 if ( FAILED(hr) )
319 {
320 wxLogApiError(_T("SHAutoComplete()"), hr);
321
322 return false;
323 }
324 return true;
325#else // !HAS_AUTOCOMPLETE
326 return false;
327#endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
328}
329
330bool wxTextEntry::AutoComplete(const wxArrayString& choices)
331{
332#ifdef HAS_AUTOCOMPLETE
333 // create an object exposing IAutoComplete interface (don't go for
334 // IAutoComplete2 immediately as, presumably, it might be not available on
335 // older systems as otherwise why do we have both -- although in practice I
336 // don't know when can this happen)
337 IAutoComplete *pAutoComplete = NULL;
338 HRESULT hr = CoCreateInstance
339 (
340 CLSID_AutoComplete,
341 NULL,
342 CLSCTX_INPROC_SERVER,
343 IID_IAutoComplete,
344 reinterpret_cast<void **>(&pAutoComplete)
345 );
346 if ( FAILED(hr) )
347 {
348 wxLogApiError(_T("CoCreateInstance(CLSID_AutoComplete)"), hr);
349 return false;
350 }
351
352 // associate it with our strings
353 wxIEnumString *pEnumString = new wxIEnumString(choices);
354 pEnumString->AddRef();
355 hr = pAutoComplete->Init(GetEditHwnd(), pEnumString, NULL, NULL);
356 pEnumString->Release();
357 if ( FAILED(hr) )
358 {
359 wxLogApiError(_T("IAutoComplete::Init"), hr);
360 return false;
361 }
362
363 // if IAutoComplete2 is available, set more user-friendly options
364 IAutoComplete2 *pAutoComplete2 = NULL;
365 hr = pAutoComplete->QueryInterface
366 (
367 IID_IAutoComplete2,
368 reinterpret_cast<void **>(&pAutoComplete2)
369 );
370 if ( SUCCEEDED(hr) )
371 {
372 pAutoComplete2->SetOptions(ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST);
373 pAutoComplete2->Release();
374 }
375
376 // the docs are unclear about when can we release it but it seems safe to
377 // do it immediately, presumably the edit control itself keeps a reference
378 // to the auto completer object
379 pAutoComplete->Release();
380 return true;
381#else // !HAS_AUTOCOMPLETE
382 wxUnusedVar(choices);
383
384 return false;
385#endif // HAS_AUTOCOMPLETE/!HAS_AUTOCOMPLETE
386}
387#endif // wxUSE_OLE
388
389// ----------------------------------------------------------------------------
390// editable state
391// ----------------------------------------------------------------------------
392
393bool wxTextEntry::IsEditable() const
394{
395 return !(::GetWindowLong(GetEditHwnd(), GWL_STYLE) & ES_READONLY);
396}
397
398void wxTextEntry::SetEditable(bool editable)
399{
400 ::SendMessage(GetEditHwnd(), EM_SETREADONLY, !editable, 0);
401}
402
403// ----------------------------------------------------------------------------
404// max length
405// ----------------------------------------------------------------------------
406
407void wxTextEntry::SetMaxLength(unsigned long len)
408{
409 if ( len >= 0xffff )
410 {
411 // this will set it to a platform-dependent maximum (much more
412 // than 64Kb under NT)
413 len = 0;
414 }
415
416 ::SendMessage(GetEditHwnd(), EM_LIMITTEXT, len, 0);
417}
418
419#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX