added wxTextEntry common base class for both wxTextCtrl and wxComboBox; refactor...
[wxWidgets.git] / src / gtk / textentry.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/textentry.cpp
3 // Purpose: wxTextEntry implementation for wxGTK
4 // Author: Vadim Zeitlin
5 // Created: 2007-09-24
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 #endif //WX_PRECOMP
28
29 #include "wx/textentry.h"
30
31 #include "wx/gtk/private.h"
32
33 // ============================================================================
34 // signal handlers implementation
35 // ============================================================================
36
37 extern "C"
38 {
39
40 // "insert_text" handler for GtkEntry
41 static void
42 wx_gtk_insert_text_callback(GtkEditable *editable,
43 const gchar *new_text,
44 gint new_text_length,
45 gint *position,
46 wxTextEntry *text)
47 {
48 // we should only be called if we have a max len limit at all
49 GtkEntry *entry = GTK_ENTRY (editable);
50
51 wxCHECK_RET( entry->text_max_length, _T("shouldn't be called") );
52
53 // check that we don't overflow the max length limit
54 //
55 // FIXME: this doesn't work when we paste a string which is going to be
56 // truncated
57 if ( entry->text_length == entry->text_max_length )
58 {
59 // we don't need to run the base class version at all
60 g_signal_stop_emission_by_name (editable, "insert_text");
61
62 text->SendMaxLenEvent();
63 }
64 }
65
66 } // extern "C"
67
68 // ============================================================================
69 // wxTextEntry implementation
70 // ============================================================================
71
72 // ----------------------------------------------------------------------------
73 // text operations
74 // ----------------------------------------------------------------------------
75
76 void wxTextEntry::WriteText(const wxString& value)
77 {
78 GtkEditable * const edit = GetEditable();
79
80 // remove the selection if there is one and suppress the text change event
81 // generated by this: we only want to generate one event for this change,
82 // not two
83 {
84 EventsSuppressor noevents(this);
85 gtk_editable_delete_selection(edit);
86 }
87
88 // insert new text at the cursor position
89 gint len = gtk_editable_get_position(edit);
90 gtk_editable_insert_text
91 (
92 edit,
93 wxGTK_CONV_FONT(value, GetEditableWindow()->GetFont()),
94 -1, // text: length: compute it using strlen()
95 &len // will be updated to position after the text end
96 );
97
98 // and move cursor to the end of new text
99 gtk_editable_set_position(edit, len);
100 }
101
102 wxString wxTextEntry::GetValue() const
103 {
104 const wxGtkString value(gtk_editable_get_chars(GetEditable(), 0, -1));
105
106 return wxGTK_CONV_BACK_FONT(value, GetEditableWindow()->GetFont());
107 }
108
109 void wxTextEntry::Remove(long from, long to)
110 {
111 gtk_editable_delete_text(GetEditable(), from, to);
112 }
113
114 // ----------------------------------------------------------------------------
115 // clipboard operations
116 // ----------------------------------------------------------------------------
117
118 void wxTextEntry::Copy()
119 {
120 gtk_editable_copy_clipboard(GetEditable());
121 }
122
123 void wxTextEntry::Cut()
124 {
125 gtk_editable_cut_clipboard(GetEditable());
126 }
127
128 void wxTextEntry::Paste()
129 {
130 gtk_editable_paste_clipboard(GetEditable());
131 }
132
133 // ----------------------------------------------------------------------------
134 // undo/redo
135 // ----------------------------------------------------------------------------
136
137 void wxTextEntry::Undo()
138 {
139 // TODO: not implemented
140 }
141
142 void wxTextEntry::Redo()
143 {
144 // TODO: not implemented
145 }
146
147 bool wxTextEntry::CanUndo() const
148 {
149 return false;
150 }
151
152 bool wxTextEntry::CanRedo() const
153 {
154 return false;
155 }
156
157 // ----------------------------------------------------------------------------
158 // insertion point
159 // ----------------------------------------------------------------------------
160
161 void wxTextEntry::SetInsertionPoint(long pos)
162 {
163 gtk_editable_set_position(GetEditable(), pos);
164 }
165
166 long wxTextEntry::GetInsertionPoint() const
167 {
168 return gtk_editable_get_position(GetEditable());
169 }
170
171 long wxTextEntry::GetLastPosition() const
172 {
173 // this can't be implemented for arbitrary GtkEditable so only do it for
174 // GtkEntries
175 GtkEntry * const entry = GTK_ENTRY(GetEditable());
176
177 return entry ? entry->text_length : - 1;
178 }
179
180 // ----------------------------------------------------------------------------
181 // selection
182 // ----------------------------------------------------------------------------
183
184 void wxTextEntry::SetSelection(long from, long to)
185 {
186 gtk_editable_select_region(GetEditable(), from, to);
187 }
188
189 void wxTextEntry::GetSelection(long *from, long *to) const
190 {
191 gint start, end;
192 if ( gtk_editable_get_selection_bounds(GetEditable(), &start, &end) )
193 {
194 // the output must always be in order, although in GTK+ it isn't
195 if ( start > end )
196 {
197 gint tmp = start;
198 start = end;
199 end = tmp;
200 }
201 }
202 else // no selection
203 {
204 // for compatibility with MSW return the empty selection at cursor
205 start =
206 end = GetInsertionPoint();
207 }
208
209 if ( from )
210 *from = start;
211
212 if ( to )
213 *to = end;
214 }
215
216 // ----------------------------------------------------------------------------
217 // editable status
218 // ----------------------------------------------------------------------------
219
220 bool wxTextEntry::IsEditable() const
221 {
222 return gtk_editable_get_editable(GetEditable());
223 }
224
225 void wxTextEntry::SetEditable(bool editable)
226 {
227 gtk_editable_set_editable(GetEditable(), editable);
228 }
229
230 // ----------------------------------------------------------------------------
231 // max text length
232 // ----------------------------------------------------------------------------
233
234 void wxTextEntry::SetMaxLength(unsigned long len)
235 {
236 GtkEntry * const entry = GTK_ENTRY(GetEditable());
237 if ( !entry )
238 return;
239
240 gtk_entry_set_max_length(entry, len);
241
242 // there is a bug in GTK+ 1.2.x: "changed" signal is emitted even if we had
243 // tried to enter more text than allowed by max text length and the text
244 // wasn't really changed
245 //
246 // to detect this and generate TEXT_MAXLEN event instead of TEXT_CHANGED
247 // one in this case we also catch "insert_text" signal
248 //
249 // when max len is set to 0 we disconnect our handler as it means that we
250 // shouldn't check anything any more
251 if ( len )
252 {
253 g_signal_connect
254 (
255 entry,
256 "insert_text",
257 G_CALLBACK(wx_gtk_insert_text_callback),
258 this
259 );
260 }
261 else // no max length
262 {
263 g_signal_handlers_disconnect_by_func
264 (
265 entry,
266 (gpointer)wx_gtk_insert_text_callback,
267 this
268 );
269 }
270 }
271
272 void wxTextEntry::SendMaxLenEvent()
273 {
274 // remember that the next changed signal is to be ignored to avoid
275 // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event
276 //IgnoreNextTextUpdate();
277
278 wxWindow * const win = const_cast<wxWindow *>(GetEditableWindow());
279 wxCommandEvent event(wxEVT_COMMAND_TEXT_MAXLEN, win->GetId());
280 event.SetEventObject(win);
281 event.SetString(GetValue());
282 win->GetEventHandler()->ProcessEvent(event);
283 }
284