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