- Moved wxApp::SendIdleEvents and wxApp::ProcessIdle into common code.
[wxWidgets.git] / src / common / textcmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: common/textcmn.cpp
3 // Purpose: implementation of platform-independent functions of wxTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 13.07.99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWindows team
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #ifdef __GNUG__
17 #pragma implementation "textctrlbase.h"
18 #endif
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_TEXTCTRL
28
29 #ifndef WX_PRECOMP
30 #include "wx/intl.h"
31 #include "wx/log.h"
32 #include "wx/textctrl.h"
33 #endif // WX_PRECOMP
34
35 #include "wx/ffile.h"
36
37 // ----------------------------------------------------------------------------
38 // macros
39 // ----------------------------------------------------------------------------
40
41 // we don't have any objects of type wxTextCtrlBase in the program, only
42 // wxTextCtrl, so this cast is safe
43 #define TEXTCTRL(ptr) ((wxTextCtrl *)(ptr))
44
45 // ============================================================================
46 // implementation
47 // ============================================================================
48
49 IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent, wxCommandEvent)
50
51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED)
52 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_ENTER)
53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_URL)
54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_MAXLEN)
55
56 // ----------------------------------------------------------------------------
57 // ctor
58 // ----------------------------------------------------------------------------
59
60 wxTextCtrlBase::wxTextCtrlBase()
61 {
62 }
63
64 wxTextCtrlBase::~wxTextCtrlBase()
65 {
66 }
67
68 // ----------------------------------------------------------------------------
69 // style functions - not implemented here
70 // ----------------------------------------------------------------------------
71
72 wxTextAttr::wxTextAttr(const wxColour& colText,
73 const wxColour& colBack,
74 const wxFont& font,
75 wxTextAttrAlignment alignment)
76 : m_colText(colText), m_colBack(colBack), m_font(font), m_textAlignment(alignment)
77 {
78 m_flags = 0;
79 m_leftIndent = 0;
80 m_rightIndent = 0;
81 if (m_colText.Ok()) m_flags |= wxTEXT_ATTR_TEXT_COLOUR;
82 if (m_colBack.Ok()) m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR;
83 if (m_font.Ok()) m_flags |= wxTEXT_ATTR_FONT;
84 if (alignment != wxTEXT_ALIGNMENT_DEFAULT)
85 m_flags |= wxTEXT_ATTR_ALIGNMENT;
86 }
87
88 void wxTextAttr::Init()
89 {
90 m_textAlignment = wxTEXT_ALIGNMENT_DEFAULT;
91 m_flags = 0;
92 m_leftIndent = 0;
93 m_rightIndent = 0;
94 }
95
96 /* static */
97 wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr,
98 const wxTextAttr& attrDef,
99 const wxTextCtrlBase *text)
100 {
101 wxFont font = attr.GetFont();
102 if ( !font.Ok() )
103 {
104 font = attrDef.GetFont();
105
106 if ( text && !font.Ok() )
107 font = text->GetFont();
108 }
109
110 wxColour colFg = attr.GetTextColour();
111 if ( !colFg.Ok() )
112 {
113 colFg = attrDef.GetTextColour();
114
115 if ( text && !colFg.Ok() )
116 colFg = text->GetForegroundColour();
117 }
118
119 wxColour colBg = attr.GetBackgroundColour();
120 if ( !colBg.Ok() )
121 {
122 colBg = attrDef.GetBackgroundColour();
123
124 if ( text && !colBg.Ok() )
125 colBg = text->GetBackgroundColour();
126 }
127
128 wxTextAttr newAttr(colFg, colBg, font);
129
130 if (attr.HasAlignment())
131 newAttr.SetAlignment(attr.GetAlignment());
132 else if (attrDef.HasAlignment())
133 newAttr.SetAlignment(attrDef.GetAlignment());
134
135 if (attr.HasTabs())
136 newAttr.SetTabs(attr.GetTabs());
137 else if (attrDef.HasTabs())
138 newAttr.SetTabs(attrDef.GetTabs());
139
140 if (attr.HasLeftIndent())
141 newAttr.SetLeftIndent(attr.GetLeftIndent());
142 else if (attrDef.HasLeftIndent())
143 newAttr.SetLeftIndent(attrDef.GetLeftIndent());
144
145 if (attr.HasRightIndent())
146 newAttr.SetRightIndent(attr.GetRightIndent());
147 else if (attrDef.HasRightIndent())
148 newAttr.SetRightIndent(attrDef.GetRightIndent());
149
150 return newAttr;
151 }
152
153 void wxTextAttr::operator= (const wxTextAttr& attr)
154 {
155 m_font = attr.m_font;
156 m_colText = attr.m_colText;
157 m_colBack = attr.m_colBack;
158 m_textAlignment = attr.m_textAlignment;
159 m_leftIndent = attr.m_leftIndent;
160 m_rightIndent = attr.m_rightIndent;
161 m_tabs = attr.m_tabs;
162 m_flags = attr.m_flags;
163 }
164
165
166 // apply styling to text range
167 bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end),
168 const wxTextAttr& WXUNUSED(style))
169 {
170 // to be implemented in derived TextCtrl classes
171 return FALSE;
172 }
173
174 // get the styling at the given position
175 bool wxTextCtrlBase::GetStyle(long WXUNUSED(position), wxTextAttr& WXUNUSED(style))
176 {
177 // to be implemented in derived TextCtrl classes
178 return FALSE;
179 }
180
181 // change default text attributes
182 bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style)
183 {
184 // keep the old attributes if the new style doesn't specify them unless the
185 // new style is empty - then reset m_defaultStyle (as there is no other way
186 // to do it)
187 if ( style.IsDefault() )
188 m_defaultStyle = style;
189 else
190 m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this);
191
192 return TRUE;
193 }
194
195 // get default text attributes
196 const wxTextAttr& wxTextCtrlBase::GetDefaultStyle() const
197 {
198 return m_defaultStyle;
199 }
200
201 // ----------------------------------------------------------------------------
202 // file IO functions
203 // ----------------------------------------------------------------------------
204
205 bool wxTextCtrlBase::LoadFile(const wxString& filename)
206 {
207 #if wxUSE_FFILE
208 wxFFile file(filename);
209 if ( file.IsOpened() )
210 {
211 wxString text;
212 if ( file.ReadAll(&text) )
213 {
214 SetValue(text);
215
216 DiscardEdits();
217
218 m_filename = filename;
219
220 return TRUE;
221 }
222 }
223
224 wxLogError(_("File couldn't be loaded."));
225 #endif // wxUSE_FFILE
226
227 return FALSE;
228 }
229
230 bool wxTextCtrlBase::SaveFile(const wxString& filename)
231 {
232 wxString filenameToUse = filename.IsEmpty() ? m_filename : filename;
233 if ( !filenameToUse )
234 {
235 // what kind of message to give? is it an error or a program bug?
236 wxLogDebug(wxT("Can't save textctrl to file without filename."));
237
238 return FALSE;
239 }
240
241 #if wxUSE_FFILE
242 wxFFile file(filename, _T("w"));
243 if ( file.IsOpened() && file.Write(GetValue()) )
244 {
245 // it's not modified any longer
246 DiscardEdits();
247
248 m_filename = filename;
249
250 return TRUE;
251 }
252
253 wxLogError(_("The text couldn't be saved."));
254 #endif // wxUSE_FFILE
255
256 return FALSE;
257 }
258
259 // ----------------------------------------------------------------------------
260 // stream-like insertion operator
261 // ----------------------------------------------------------------------------
262
263 wxTextCtrl& wxTextCtrlBase::operator<<(const wxString& s)
264 {
265 AppendText(s);
266 return *TEXTCTRL(this);
267 }
268
269 wxTextCtrl& wxTextCtrlBase::operator<<(float f)
270 {
271 wxString str;
272 str.Printf(wxT("%.2f"), f);
273 AppendText(str);
274 return *TEXTCTRL(this);
275 }
276
277 wxTextCtrl& wxTextCtrlBase::operator<<(double d)
278 {
279 wxString str;
280 str.Printf(wxT("%.2f"), d);
281 AppendText(str);
282 return *TEXTCTRL(this);
283 }
284
285 wxTextCtrl& wxTextCtrlBase::operator<<(int i)
286 {
287 wxString str;
288 str.Printf(wxT("%d"), i);
289 AppendText(str);
290 return *TEXTCTRL(this);
291 }
292
293 wxTextCtrl& wxTextCtrlBase::operator<<(long i)
294 {
295 wxString str;
296 str.Printf(wxT("%ld"), i);
297 AppendText(str);
298 return *TEXTCTRL(this);
299 }
300
301 wxTextCtrl& wxTextCtrlBase::operator<<(const wxChar c)
302 {
303 return operator<<(wxString(c));
304 }
305
306 // ----------------------------------------------------------------------------
307 // streambuf methods implementation
308 // ----------------------------------------------------------------------------
309
310 #ifndef NO_TEXT_WINDOW_STREAM
311
312 int wxTextCtrlBase::overflow(int c)
313 {
314 AppendText((wxChar)c);
315
316 // return something different from EOF
317 return 0;
318 }
319
320 #endif // NO_TEXT_WINDOW_STREAM
321
322 // ----------------------------------------------------------------------------
323 // clipboard stuff
324 // ----------------------------------------------------------------------------
325
326 bool wxTextCtrlBase::CanCopy() const
327 {
328 // can copy if there's a selection
329 long from, to;
330 GetSelection(&from, &to);
331 return from != to;
332 }
333
334 bool wxTextCtrlBase::CanCut() const
335 {
336 // can cut if there's a selection and if we're not read only
337 return CanCopy() && IsEditable();
338 }
339
340 bool wxTextCtrlBase::CanPaste() const
341 {
342 // can paste if we are not read only
343 return IsEditable();
344 }
345
346 // ----------------------------------------------------------------------------
347 // emulating key presses
348 // ----------------------------------------------------------------------------
349
350 bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& event)
351 {
352 // the generic version is unused in wxMSW
353 #ifndef __WIN32__
354 wxChar ch = 0;
355 int keycode = event.GetKeyCode();
356 switch ( keycode )
357 {
358 case WXK_NUMPAD0:
359 case WXK_NUMPAD1:
360 case WXK_NUMPAD2:
361 case WXK_NUMPAD3:
362 case WXK_NUMPAD4:
363 case WXK_NUMPAD5:
364 case WXK_NUMPAD6:
365 case WXK_NUMPAD7:
366 case WXK_NUMPAD8:
367 case WXK_NUMPAD9:
368 ch = _T('0') + keycode - WXK_NUMPAD0;
369 break;
370
371 case WXK_MULTIPLY:
372 case WXK_NUMPAD_MULTIPLY:
373 ch = _T('*');
374 break;
375
376 case WXK_ADD:
377 case WXK_NUMPAD_ADD:
378 ch = _T('+');
379 break;
380
381 case WXK_SUBTRACT:
382 case WXK_NUMPAD_SUBTRACT:
383 ch = _T('-');
384 break;
385
386 case WXK_DECIMAL:
387 case WXK_NUMPAD_DECIMAL:
388 ch = _T('.');
389 break;
390
391 case WXK_DIVIDE:
392 case WXK_NUMPAD_DIVIDE:
393 ch = _T('/');
394 break;
395
396 case WXK_DELETE:
397 case WXK_NUMPAD_DELETE:
398 // delete the character at cursor
399 {
400 const long pos = GetInsertionPoint(),
401 last = GetLastPosition();
402 if ( pos < last )
403 Remove(pos, pos + 1);
404 }
405 break;
406
407 case WXK_BACK:
408 // delete the character before the cursor
409 {
410 const long pos = GetInsertionPoint();
411 if ( pos > 0 )
412 Remove(pos - 1, pos);
413 }
414 break;
415
416 default:
417 if ( keycode < 256 && keycode >= 0 && wxIsprint(keycode) )
418 {
419 // FIXME this is not going to work for non letters...
420 if ( !event.ShiftDown() )
421 {
422 keycode = wxTolower(keycode);
423 }
424
425 ch = (wxChar)keycode;
426 }
427 else
428 {
429 ch = _T('\0');
430 }
431 }
432
433 if ( ch )
434 {
435 WriteText(ch);
436
437 return TRUE;
438 }
439 #endif // !__WIN32__
440
441 return FALSE;
442 }
443
444 // ----------------------------------------------------------------------------
445 // selection and ranges
446 // ----------------------------------------------------------------------------
447
448 void wxTextCtrlBase::SelectAll()
449 {
450 SetSelection(0, GetLastPosition());
451 }
452
453 wxString wxTextCtrlBase::GetStringSelection() const
454 {
455 long from, to;
456 GetSelection(&from, &to);
457
458 return GetRange(from, to);
459 }
460
461 wxString wxTextCtrlBase::GetRange(long from, long to) const
462 {
463 wxString sel;
464 if ( from < to )
465 {
466 sel = GetValue().Mid(from, to - from);
467 }
468
469 return sel;
470 }
471
472 // do the window-specific processing after processing the update event
473 void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
474 {
475 if ( event.GetSetEnabled() )
476 Enable(event.GetEnabled());
477
478 if ( event.GetSetText() )
479 {
480 if ( event.GetText() != GetValue() )
481 SetValue(event.GetText());
482 }
483 }
484
485
486 #else // !wxUSE_TEXTCTRL
487
488 // define this one even if !wxUSE_TEXTCTRL because it is also used by other
489 // controls (wxComboBox and wxSpinCtrl)
490 #include "wx/event.h"
491
492 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED)
493
494 #endif // wxUSE_TEXTCTRL/!wxUSE_TEXTCTRL
495