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