]> git.saurik.com Git - wxWidgets.git/blob - src/common/textentrycmn.cpp
Update all controls using in-place editors to handle Escape/Return correctly.
[wxWidgets.git] / src / common / textentrycmn.cpp
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
29 #include "wx/window.h"
30 #include "wx/dataobj.h"
31 #endif //WX_PRECOMP
32
33 #include "wx/textentry.h"
34 #include "wx/textcompleter.h"
35 #include "wx/clipbrd.h"
36
37 // ----------------------------------------------------------------------------
38 // wxTextEntryHintData
39 // ----------------------------------------------------------------------------
40
41 class WXDLLIMPEXP_CORE wxTextEntryHintData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
42 {
43 public:
44 wxTextEntryHintData(wxTextEntryBase *entry, wxWindow *win)
45 : m_entry(entry),
46 m_win(win),
47 m_text(m_entry->GetValue())
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);
53 wxBIND_OR_CONNECT_HACK(win, wxEVT_COMMAND_TEXT_UPDATED,
54 wxCommandEventHandler,
55 wxTextEntryHintData::OnTextChanged, this);
56 }
57
58 // default dtor is ok
59
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; }
63
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.
68 void SetHintString(const wxString& hint)
69 {
70 m_hint = hint;
71
72 if ( !m_win->HasFocus() )
73 ShowHintIfAppropriate();
74 //else: The new hint will be shown later when we lose focus.
75 }
76
77 const wxString& GetHintString() const { return m_hint; }
78
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
93 private:
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()
97 {
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() )
115 {
116 m_win->SetForegroundColour(m_colFg);
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();
128
129 m_entry->DoSetValue(wxString(), wxTextEntryBase::SetValue_NoEvent);
130 }
131
132 event.Skip();
133 }
134
135 void OnKillFocus(wxFocusEvent& event)
136 {
137 // Restore the hint if the user didn't enter anything.
138 ShowHintIfAppropriate();
139
140 event.Skip();
141 }
142
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.
151 HandleTextUpdate(m_entry->DoGetValue());
152
153 event.Skip();
154 }
155
156
157 // the text control we're associated with (as its interface and its window)
158 wxTextEntryBase * const m_entry;
159 wxWindow * const m_win;
160
161 // the original foreground colour of m_win before we changed it
162 wxColour m_colFg;
163
164 // The hint passed to wxTextEntry::SetHint(), never empty.
165 wxString m_hint;
166
167 // The real text of the window.
168 wxString m_text;
169
170
171 wxDECLARE_NO_COPY_CLASS(wxTextEntryHintData);
172 };
173
174 // ============================================================================
175 // wxTextEntryBase implementation
176 // ============================================================================
177
178 wxTextEntryBase::~wxTextEntryBase()
179 {
180 delete m_hintData;
181 }
182
183 // ----------------------------------------------------------------------------
184 // text accessors
185 // ----------------------------------------------------------------------------
186
187 wxString wxTextEntryBase::GetValue() const
188 {
189 return m_hintData ? m_hintData->GetText() : DoGetValue();
190 }
191
192 wxString wxTextEntryBase::GetRange(long from, long to) const
193 {
194 wxString sel;
195 wxString value = GetValue();
196
197 if ( from < to && (long)value.length() >= to )
198 {
199 sel = value.substr(from, to - from);
200 }
201
202 return sel;
203 }
204
205 // ----------------------------------------------------------------------------
206 // text operations
207 // ----------------------------------------------------------------------------
208
209 void 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
219 void wxTextEntryBase::AppendText(const wxString& text)
220 {
221 SetInsertionPointEnd();
222 WriteText(text);
223 }
224
225 void wxTextEntryBase::DoSetValue(const wxString& value, int flags)
226 {
227 EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent));
228
229 SelectAll();
230 WriteText(value);
231
232 SetInsertionPoint(0);
233 }
234
235 void wxTextEntryBase::Replace(long from, long to, const wxString& value)
236 {
237 {
238 EventsSuppressor noevents(this);
239 Remove(from, to);
240 }
241
242 SetInsertionPoint(from);
243 WriteText(value);
244 }
245
246 // ----------------------------------------------------------------------------
247 // selection
248 // ----------------------------------------------------------------------------
249
250 bool wxTextEntryBase::HasSelection() const
251 {
252 long from, to;
253 GetSelection(&from, &to);
254
255 return from < to;
256 }
257
258 void wxTextEntryBase::RemoveSelection()
259 {
260 long from, to;
261 GetSelection(& from, & to);
262 if (from != -1 && to != -1)
263 Remove(from, to);
264 }
265
266 wxString wxTextEntryBase::GetStringSelection() const
267 {
268 long from, to;
269 GetSelection(&from, &to);
270
271 return GetRange(from, to);
272 }
273
274 // ----------------------------------------------------------------------------
275 // clipboard
276 // ----------------------------------------------------------------------------
277
278 bool wxTextEntryBase::CanCopy() const
279 {
280 return HasSelection();
281 }
282
283 bool wxTextEntryBase::CanCut() const
284 {
285 return CanCopy() && IsEditable();
286 }
287
288 bool wxTextEntryBase::CanPaste() const
289 {
290 if ( IsEditable() )
291 {
292 #if wxUSE_CLIPBOARD
293 // check if there is any text on the clipboard
294 if ( wxTheClipboard->IsSupported(wxDF_TEXT)
295 #if wxUSE_UNICODE
296 || wxTheClipboard->IsSupported(wxDF_UNICODETEXT)
297 #endif // wxUSE_UNICODE
298 )
299 {
300 return true;
301 }
302 #endif // wxUSE_CLIPBOARD
303 }
304
305 return false;
306 }
307
308 // ----------------------------------------------------------------------------
309 // hints support
310 // ----------------------------------------------------------------------------
311
312 bool wxTextEntryBase::SetHint(const wxString& hint)
313 {
314 if ( !hint.empty() )
315 {
316 if ( !m_hintData )
317 m_hintData = new wxTextEntryHintData(this, GetEditableWindow());
318
319 m_hintData->SetHintString(hint);
320 }
321 else if ( m_hintData )
322 {
323 // Setting empty hint removes any currently set one.
324 delete m_hintData;
325 m_hintData = NULL;
326 }
327 //else: Setting empty hint when we don't have any doesn't do anything.
328
329 return true;
330 }
331
332 wxString wxTextEntryBase::GetHint() const
333 {
334 return m_hintData ? m_hintData->GetHintString() : wxString();
335 }
336
337 // ----------------------------------------------------------------------------
338 // margins support
339 // ----------------------------------------------------------------------------
340
341 bool wxTextEntryBase::DoSetMargins(const wxPoint& WXUNUSED(pt))
342 {
343 return false;
344 }
345
346 wxPoint wxTextEntryBase::DoGetMargins() const
347 {
348 return wxPoint(-1, -1);
349 }
350
351 // ----------------------------------------------------------------------------
352 // events
353 // ----------------------------------------------------------------------------
354
355 /* static */
356 bool wxTextEntryBase::SendTextUpdatedEvent(wxWindow *win)
357 {
358 wxCHECK_MSG( win, false, "can't send an event without a window" );
359
360 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, win->GetId());
361
362 // do not do this as it could be very inefficient if the text control
363 // contains a lot of text and we're not using ref-counted wxString
364 // implementation -- instead, event.GetString() will query the control for
365 // its current text if needed
366 //event.SetString(win->GetValue());
367
368 event.SetEventObject(win);
369 return win->HandleWindowEvent(event);
370 }
371
372 // ----------------------------------------------------------------------------
373 // auto-completion stubs
374 // ----------------------------------------------------------------------------
375
376 wxTextCompleter::~wxTextCompleter()
377 {
378 }
379
380 bool wxTextCompleterSimple::Start(const wxString& prefix)
381 {
382 m_index = 0;
383 m_completions.clear();
384 GetCompletions(prefix, m_completions);
385
386 return !m_completions.empty();
387 }
388
389 wxString wxTextCompleterSimple::GetNext()
390 {
391 if ( m_index == m_completions.size() )
392 return wxString();
393
394 return m_completions[m_index++];
395 }
396
397 bool wxTextEntryBase::DoAutoCompleteCustom(wxTextCompleter *completer)
398 {
399 // We don't do anything here but we still need to delete the completer for
400 // consistency with the ports that do implement this method and take
401 // ownership of the pointer.
402 delete completer;
403
404 return false;
405 }
406
407 #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX