]> git.saurik.com Git - wxWidgets.git/blame - src/common/textentrycmn.cpp
fixing mem leak
[wxWidgets.git] / src / common / textentrycmn.cpp
CommitLineData
0ec1179b
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/common/textentrycmn.cpp
3// Purpose: wxTextEntryBase implementation
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#if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
27
28#ifndef WX_PRECOMP
86116620
RR
29 #include "wx/window.h"
30 #include "wx/dataobj.h"
0ec1179b
VZ
31#endif //WX_PRECOMP
32
33#include "wx/textentry.h"
ea98f11c 34#include "wx/textcompleter.h"
fa2f57be 35#include "wx/clipbrd.h"
0ec1179b 36
63f7d502
VZ
37// ----------------------------------------------------------------------------
38// wxTextEntryHintData
39// ----------------------------------------------------------------------------
40
41class WXDLLIMPEXP_CORE wxTextEntryHintData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
42{
43public:
44 wxTextEntryHintData(wxTextEntryBase *entry, wxWindow *win)
45 : m_entry(entry),
a7aeddac
VZ
46 m_win(win),
47 m_text(m_entry->GetValue())
63f7d502
VZ
48 {
49 wxBIND_OR_CONNECT_HACK(win, wxEVT_SET_FOCUS, wxFocusEventHandler,
50 wxTextEntryHintData::OnSetFocus, this);
51 wxBIND_OR_CONNECT_HACK(win, wxEVT_KILL_FOCUS, wxFocusEventHandler,
52 wxTextEntryHintData::OnKillFocus, this);
a7aeddac
VZ
53 wxBIND_OR_CONNECT_HACK(win, wxEVT_COMMAND_TEXT_UPDATED,
54 wxCommandEventHandler,
55 wxTextEntryHintData::OnTextChanged, this);
63f7d502
VZ
56 }
57
58 // default dtor is ok
59
a7aeddac
VZ
60 // Get the real text of the control such as it was before we replaced it
61 // with the hint.
62 const wxString& GetText() const { return m_text; }
135b23b2 63
a7aeddac
VZ
64 // Set the hint to show, shouldn't be empty normally.
65 //
66 // This should be called after creating a new wxTextEntryHintData object
67 // and may be called more times in the future.
63f7d502
VZ
68 void SetHintString(const wxString& hint)
69 {
70 m_hint = hint;
71
a7aeddac
VZ
72 if ( !m_win->HasFocus() )
73 ShowHintIfAppropriate();
74 //else: The new hint will be shown later when we lose focus.
63f7d502
VZ
75 }
76
77 const wxString& GetHintString() const { return m_hint; }
78
7bfc104b
VZ
79 // This is called whenever the text control contents changes.
80 //
81 // We call it ourselves when this change generates an event but it's also
82 // necessary to call it explicitly from wxTextEntry::ChangeValue() as it,
83 // by design, does not generate any events.
84 void HandleTextUpdate(const wxString& text)
85 {
86 m_text = text;
87
88 // If we're called because of a call to Set or ChangeValue(), the
89 // control may still have the hint text colour, reset it in this case.
90 RestoreTextColourIfNecessary();
91 }
92
63f7d502 93private:
a7aeddac
VZ
94 // Show the hint in the window if we should do it, i.e. if the window
95 // doesn't have any text of its own.
96 void ShowHintIfAppropriate()
63f7d502 97 {
a7aeddac
VZ
98 // Never overwrite existing window text.
99 if ( !m_text.empty() )
100 return;
101
102 // Save the old text colour and set a more inconspicuous one for the
103 // hint.
104 m_colFg = m_win->GetForegroundColour();
105 m_win->SetForegroundColour(*wxLIGHT_GREY);
106
107 m_entry->DoSetValue(m_hint, wxTextEntryBase::SetValue_NoEvent);
108 }
109
110 // Restore the original text colour if we had changed it to show the hint
111 // and not restored it yet.
112 void RestoreTextColourIfNecessary()
113 {
114 if ( m_colFg.IsOk() )
63f7d502 115 {
63f7d502 116 m_win->SetForegroundColour(m_colFg);
a7aeddac
VZ
117 m_colFg = wxColour();
118 }
119 }
120
121 void OnSetFocus(wxFocusEvent& event)
122 {
123 // If we had been showing the hint before, remove it now and restore
124 // the normal colour.
125 if ( m_text.empty() )
126 {
127 RestoreTextColourIfNecessary();
135b23b2 128
a7aeddac 129 m_entry->DoSetValue(wxString(), wxTextEntryBase::SetValue_NoEvent);
63f7d502
VZ
130 }
131
132 event.Skip();
133 }
134
135 void OnKillFocus(wxFocusEvent& event)
136 {
a7aeddac
VZ
137 // Restore the hint if the user didn't enter anything.
138 ShowHintIfAppropriate();
63f7d502 139
a7aeddac
VZ
140 event.Skip();
141 }
135b23b2 142
a7aeddac
VZ
143 void OnTextChanged(wxCommandEvent& event)
144 {
145 // Update the stored window text.
146 //
147 // Notice that we can't use GetValue() nor wxCommandEvent::GetString()
148 // which uses it internally because this would just forward back to us
149 // so go directly to the private method which returns the real control
150 // contents.
7bfc104b 151 HandleTextUpdate(m_entry->DoGetValue());
63f7d502
VZ
152
153 event.Skip();
154 }
155
a7aeddac 156
135b23b2 157 // the text control we're associated with (as its interface and its window)
63f7d502
VZ
158 wxTextEntryBase * const m_entry;
159 wxWindow * const m_win;
160
135b23b2 161 // the original foreground colour of m_win before we changed it
63f7d502
VZ
162 wxColour m_colFg;
163
a7aeddac 164 // The hint passed to wxTextEntry::SetHint(), never empty.
63f7d502
VZ
165 wxString m_hint;
166
a7aeddac
VZ
167 // The real text of the window.
168 wxString m_text;
169
135b23b2 170
63f7d502
VZ
171 wxDECLARE_NO_COPY_CLASS(wxTextEntryHintData);
172};
173
0ec1179b
VZ
174// ============================================================================
175// wxTextEntryBase implementation
176// ============================================================================
177
63f7d502
VZ
178wxTextEntryBase::~wxTextEntryBase()
179{
180 delete m_hintData;
181}
182
183// ----------------------------------------------------------------------------
135b23b2 184// text accessors
63f7d502
VZ
185// ----------------------------------------------------------------------------
186
135b23b2
VZ
187wxString wxTextEntryBase::GetValue() const
188{
a7aeddac 189 return m_hintData ? m_hintData->GetText() : DoGetValue();
135b23b2
VZ
190}
191
0ec1179b
VZ
192wxString wxTextEntryBase::GetRange(long from, long to) const
193{
194 wxString sel;
e9863f4e 195 wxString value = GetValue();
2b42a870
VZ
196
197 if ( from < to && (long)value.length() >= to )
0ec1179b 198 {
2b42a870 199 sel = value.substr(from, to - from);
0ec1179b
VZ
200 }
201
202 return sel;
203}
204
135b23b2
VZ
205// ----------------------------------------------------------------------------
206// text operations
207// ----------------------------------------------------------------------------
208
7bfc104b
VZ
209void wxTextEntryBase::ChangeValue(const wxString& value)
210{
211 DoSetValue(value, SetValue_NoEvent);
212
213 // As we didn't generate any events for wxTextEntryHintData to catch,
214 // notify it explicitly about our changed contents.
215 if ( m_hintData )
216 m_hintData->HandleTextUpdate(value);
217}
218
0ec1179b
VZ
219void wxTextEntryBase::AppendText(const wxString& text)
220{
221 SetInsertionPointEnd();
222 WriteText(text);
223}
224
225void wxTextEntryBase::DoSetValue(const wxString& value, int flags)
226{
c87df234
VZ
227 if ( value != GetValue() )
228 {
229 EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent));
0ec1179b 230
c87df234
VZ
231 SelectAll();
232 WriteText(value);
233 }
234 else // Same value, no need to do anything.
235 {
236 // Except that we still need to generate the event for consistency with
237 // the normal case when the text does change.
0b613906
VZ
238 if ( flags & SetValue_SendEvent )
239 SendTextUpdatedEvent(GetEditableWindow());
c87df234 240 }
a5125dc6
VZ
241
242 SetInsertionPoint(0);
0ec1179b
VZ
243}
244
245void wxTextEntryBase::Replace(long from, long to, const wxString& value)
246{
247 {
248 EventsSuppressor noevents(this);
249 Remove(from, to);
250 }
251
059979d8 252 SetInsertionPoint(from);
0ec1179b
VZ
253 WriteText(value);
254}
255
63f7d502
VZ
256// ----------------------------------------------------------------------------
257// selection
258// ----------------------------------------------------------------------------
259
0ec1179b
VZ
260bool wxTextEntryBase::HasSelection() const
261{
262 long from, to;
263 GetSelection(&from, &to);
264
265 return from < to;
266}
267
5a25f858
VZ
268void wxTextEntryBase::RemoveSelection()
269{
270 long from, to;
271 GetSelection(& from, & to);
272 if (from != -1 && to != -1)
273 Remove(from, to);
274}
275
0ec1179b
VZ
276wxString wxTextEntryBase::GetStringSelection() const
277{
278 long from, to;
279 GetSelection(&from, &to);
280
281 return GetRange(from, to);
282}
283
63f7d502
VZ
284// ----------------------------------------------------------------------------
285// clipboard
286// ----------------------------------------------------------------------------
287
0ec1179b
VZ
288bool wxTextEntryBase::CanCopy() const
289{
290 return HasSelection();
291}
292
293bool wxTextEntryBase::CanCut() const
294{
295 return CanCopy() && IsEditable();
296}
297
298bool wxTextEntryBase::CanPaste() const
299{
fa2f57be
VZ
300 if ( IsEditable() )
301 {
302#if wxUSE_CLIPBOARD
303 // check if there is any text on the clipboard
fa9cd5d3
VZ
304 if ( wxTheClipboard->IsSupported(wxDF_TEXT)
305#if wxUSE_UNICODE
306 || wxTheClipboard->IsSupported(wxDF_UNICODETEXT)
307#endif // wxUSE_UNICODE
308 )
309 {
fa2f57be 310 return true;
fa9cd5d3 311 }
fa2f57be
VZ
312#endif // wxUSE_CLIPBOARD
313 }
314
315 return false;
0ec1179b
VZ
316}
317
63f7d502
VZ
318// ----------------------------------------------------------------------------
319// hints support
320// ----------------------------------------------------------------------------
321
322bool wxTextEntryBase::SetHint(const wxString& hint)
323{
a7aeddac
VZ
324 if ( !hint.empty() )
325 {
326 if ( !m_hintData )
327 m_hintData = new wxTextEntryHintData(this, GetEditableWindow());
63f7d502 328
a7aeddac
VZ
329 m_hintData->SetHintString(hint);
330 }
331 else if ( m_hintData )
332 {
333 // Setting empty hint removes any currently set one.
334 delete m_hintData;
335 m_hintData = NULL;
336 }
337 //else: Setting empty hint when we don't have any doesn't do anything.
63f7d502
VZ
338
339 return true;
340}
341
342wxString wxTextEntryBase::GetHint() const
343{
344 return m_hintData ? m_hintData->GetHintString() : wxString();
345}
346
0847e36e
JS
347// ----------------------------------------------------------------------------
348// margins support
349// ----------------------------------------------------------------------------
350
351bool wxTextEntryBase::DoSetMargins(const wxPoint& WXUNUSED(pt))
352{
353 return false;
354}
355
356wxPoint wxTextEntryBase::DoGetMargins() const
357{
358 return wxPoint(-1, -1);
359}
360
50135807
VZ
361// ----------------------------------------------------------------------------
362// events
363// ----------------------------------------------------------------------------
364
365/* static */
366bool wxTextEntryBase::SendTextUpdatedEvent(wxWindow *win)
367{
368 wxCHECK_MSG( win, false, "can't send an event without a window" );
369
370 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, win->GetId());
371
372 // do not do this as it could be very inefficient if the text control
373 // contains a lot of text and we're not using ref-counted wxString
374 // implementation -- instead, event.GetString() will query the control for
375 // its current text if needed
376 //event.SetString(win->GetValue());
377
378 event.SetEventObject(win);
379 return win->HandleWindowEvent(event);
380}
381
ea98f11c
VZ
382// ----------------------------------------------------------------------------
383// auto-completion stubs
384// ----------------------------------------------------------------------------
385
386wxTextCompleter::~wxTextCompleter()
387{
388}
389
85047589
VZ
390bool wxTextCompleterSimple::Start(const wxString& prefix)
391{
392 m_index = 0;
393 m_completions.clear();
394 GetCompletions(prefix, m_completions);
395
396 return !m_completions.empty();
397}
398
399wxString wxTextCompleterSimple::GetNext()
400{
401 if ( m_index == m_completions.size() )
402 return wxString();
403
404 return m_completions[m_index++];
405}
406
ea98f11c
VZ
407bool wxTextEntryBase::DoAutoCompleteCustom(wxTextCompleter *completer)
408{
409 // We don't do anything here but we still need to delete the completer for
410 // consistency with the ports that do implement this method and take
411 // ownership of the pointer.
412 delete completer;
413
414 return false;
415}
416
0ec1179b 417#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX