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