1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/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: textcmn.cpp 62095 2009-09-24 18:20:21Z JS $
8 // Copyright:   (c) wxWidgets team
9 // Licence:     wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // for compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18 
19 #ifdef __BORLANDC__
20     #pragma hdrstop
21 #endif
22 
23 #ifndef WX_PRECOMP
24     #include "wx/event.h"
25 #endif // WX_PRECOMP
26 
27 #if wxUSE_TEXTCTRL
28 
29 #include "wx/textctrl.h"
30 
31 #ifndef WX_PRECOMP
32     #include "wx/intl.h"
33     #include "wx/log.h"
34 #endif // WX_PRECOMP
35 
36 #include "wx/ffile.h"
37 
38 // ----------------------------------------------------------------------------
39 // macros
40 // ----------------------------------------------------------------------------
41 
42 // we don't have any objects of type wxTextCtrlBase in the program, only
43 // wxTextCtrl, so this cast is safe
44 #define TEXTCTRL(ptr)   ((wxTextCtrl *)(ptr))
45 
46 // ============================================================================
47 // implementation
48 // ============================================================================
49 
IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent,wxCommandEvent)50 IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent, wxCommandEvent)
51 
52 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED)
53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_ENTER)
54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_URL)
55 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_MAXLEN)
56 
57 IMPLEMENT_ABSTRACT_CLASS(wxTextCtrlBase, wxControl)
58 
59 // ----------------------------------------------------------------------------
60 // style functions - not implemented here
61 // ----------------------------------------------------------------------------
62 
63 wxTextAttr::wxTextAttr(const wxColour& colText,
64                const wxColour& colBack,
65                const wxFont& font,
66                wxTextAttrAlignment alignment)
67     : m_colText(colText), m_colBack(colBack), m_font(font), m_textAlignment(alignment)
68 {
69     m_flags = 0;
70     m_leftIndent = 0;
71     m_leftSubIndent = 0;
72     m_rightIndent = 0;
73     if (m_colText.Ok()) m_flags |= wxTEXT_ATTR_TEXT_COLOUR;
74     if (m_colBack.Ok()) m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR;
75     if (m_font.Ok()) m_flags |= wxTEXT_ATTR_FONT;
76     if (alignment != wxTEXT_ALIGNMENT_DEFAULT)
77         m_flags |= wxTEXT_ATTR_ALIGNMENT;
78 }
79 
Init()80 void wxTextAttr::Init()
81 {
82     m_textAlignment = wxTEXT_ALIGNMENT_DEFAULT;
83     m_flags = 0;
84     m_leftIndent = 0;
85     m_leftSubIndent = 0;
86     m_rightIndent = 0;
87 }
88 
89 /* static */
Combine(const wxTextAttr & attr,const wxTextAttr & attrDef,const wxTextCtrlBase * text)90 wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr,
91                                const wxTextAttr& attrDef,
92                                const wxTextCtrlBase *text)
93 {
94     wxFont font = attr.GetFont();
95     if ( !font.Ok() )
96     {
97         font = attrDef.GetFont();
98 
99         if ( text && !font.Ok() )
100             font = text->GetFont();
101     }
102 
103     wxColour colFg = attr.GetTextColour();
104     if ( !colFg.Ok() )
105     {
106         colFg = attrDef.GetTextColour();
107 
108         if ( text && !colFg.Ok() )
109             colFg = text->GetForegroundColour();
110     }
111 
112     wxColour colBg = attr.GetBackgroundColour();
113     if ( !colBg.Ok() )
114     {
115         colBg = attrDef.GetBackgroundColour();
116 
117         if ( text && !colBg.Ok() )
118             colBg = text->GetBackgroundColour();
119     }
120 
121     wxTextAttr newAttr(colFg, colBg, font);
122 
123     if (attr.HasAlignment())
124         newAttr.SetAlignment(attr.GetAlignment());
125     else if (attrDef.HasAlignment())
126         newAttr.SetAlignment(attrDef.GetAlignment());
127 
128     if (attr.HasTabs())
129         newAttr.SetTabs(attr.GetTabs());
130     else if (attrDef.HasTabs())
131         newAttr.SetTabs(attrDef.GetTabs());
132 
133     if (attr.HasLeftIndent())
134         newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent());
135     else if (attrDef.HasLeftIndent())
136         newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent());
137 
138     if (attr.HasRightIndent())
139         newAttr.SetRightIndent(attr.GetRightIndent());
140     else if (attrDef.HasRightIndent())
141         newAttr.SetRightIndent(attrDef.GetRightIndent());
142 
143     return newAttr;
144 }
145 
operator =(const wxTextAttr & attr)146 void wxTextAttr::operator= (const wxTextAttr& attr)
147 {
148     m_font = attr.m_font;
149     m_colText = attr.m_colText;
150     m_colBack = attr.m_colBack;
151     m_textAlignment = attr.m_textAlignment;
152     m_leftIndent = attr.m_leftIndent;
153     m_leftSubIndent = attr.m_leftSubIndent;
154     m_rightIndent = attr.m_rightIndent;
155     m_tabs = attr.m_tabs;
156     m_flags = attr.m_flags;
157 }
158 
159 
160 // apply styling to text range
SetStyle(long WXUNUSED (start),long WXUNUSED (end),const wxTextAttr & WXUNUSED (style))161 bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end),
162                               const wxTextAttr& WXUNUSED(style))
163 {
164     // to be implemented in derived TextCtrl classes
165     return false;
166 }
167 
168 // get the styling at the given position
GetStyle(long WXUNUSED (position),wxTextAttr & WXUNUSED (style))169 bool wxTextCtrlBase::GetStyle(long WXUNUSED(position), wxTextAttr& WXUNUSED(style))
170 {
171     // to be implemented in derived TextCtrl classes
172     return false;
173 }
174 
175 // change default text attributes
SetDefaultStyle(const wxTextAttr & style)176 bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style)
177 {
178     // keep the old attributes if the new style doesn't specify them unless the
179     // new style is empty - then reset m_defaultStyle (as there is no other way
180     // to do it)
181     if ( style.IsDefault() )
182         m_defaultStyle = style;
183     else
184         m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this);
185 
186     return true;
187 }
188 
189 // get default text attributes
GetDefaultStyle() const190 const wxTextAttr& wxTextCtrlBase::GetDefaultStyle() const
191 {
192     return m_defaultStyle;
193 }
194 
195 // ----------------------------------------------------------------------------
196 // file IO functions
197 // ----------------------------------------------------------------------------
198 
DoLoadFile(const wxString & filename,int WXUNUSED (fileType))199 bool wxTextCtrlBase::DoLoadFile(const wxString& filename, int WXUNUSED(fileType))
200 {
201 #if wxUSE_FFILE
202     wxFFile file(filename);
203     if ( file.IsOpened() )
204     {
205         wxString text;
206         if ( file.ReadAll(&text) )
207         {
208             SetValue(text);
209 
210             DiscardEdits();
211 
212             m_filename = filename;
213 
214             return true;
215         }
216     }
217 
218     wxLogError(_("File couldn't be loaded."));
219 #endif // wxUSE_FFILE
220 
221     return false;
222 }
223 
SaveFile(const wxString & filename,int fileType)224 bool wxTextCtrlBase::SaveFile(const wxString& filename, int fileType)
225 {
226     wxString filenameToUse = filename.empty() ? m_filename : filename;
227     if ( filenameToUse.empty() )
228     {
229         // what kind of message to give? is it an error or a program bug?
230         wxLogDebug(wxT("Can't save textctrl to file without filename."));
231 
232         return false;
233     }
234 
235     return DoSaveFile(filenameToUse, fileType);
236 }
237 
DoSaveFile(const wxString & filename,int WXUNUSED (fileType))238 bool wxTextCtrlBase::DoSaveFile(const wxString& filename, int WXUNUSED(fileType))
239 {
240 #if wxUSE_FFILE
241     wxFFile file(filename, _T("w"));
242     if ( file.IsOpened() && file.Write(GetValue()) )
243     {
244         // if it worked, save for future calls
245         m_filename = filename;
246 
247         // it's not modified any longer
248         DiscardEdits();
249 
250         return true;
251     }
252 #endif // wxUSE_FFILE
253 
254     wxLogError(_("The text couldn't be saved."));
255 
256     return false;
257 }
258 
259 // ----------------------------------------------------------------------------
260 // stream-like insertion operator
261 // ----------------------------------------------------------------------------
262 
operator <<(const wxString & s)263 wxTextCtrl& wxTextCtrlBase::operator<<(const wxString& s)
264 {
265     AppendText(s);
266     return *TEXTCTRL(this);
267 }
268 
operator <<(float f)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 
operator <<(double d)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 
operator <<(int i)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 
operator <<(long i)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 
operator <<(const wxChar c)301 wxTextCtrl& wxTextCtrlBase::operator<<(const wxChar c)
302 {
303     return operator<<(wxString(c));
304 }
305 
306 // ----------------------------------------------------------------------------
307 // streambuf methods implementation
308 // ----------------------------------------------------------------------------
309 
310 #if wxHAS_TEXT_WINDOW_STREAM
311 
overflow(int c)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 // wxHAS_TEXT_WINDOW_STREAM
321 
322 // ----------------------------------------------------------------------------
323 // clipboard stuff
324 // ----------------------------------------------------------------------------
325 
CanCopy() const326 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 
CanCut() const334 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 
CanPaste() const340 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 #ifdef __WIN32__
351 // the generic version is unused in wxMSW
EmulateKeyPress(const wxKeyEvent & WXUNUSED (event))352 bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& WXUNUSED(event))
353 {
354     return false;
355 }
356 #else // !__WIN32__
EmulateKeyPress(const wxKeyEvent & event)357 bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& event)
358 {
359     wxChar ch = 0;
360     int keycode = event.GetKeyCode();
361     switch ( keycode )
362     {
363         case WXK_NUMPAD0:
364         case WXK_NUMPAD1:
365         case WXK_NUMPAD2:
366         case WXK_NUMPAD3:
367         case WXK_NUMPAD4:
368         case WXK_NUMPAD5:
369         case WXK_NUMPAD6:
370         case WXK_NUMPAD7:
371         case WXK_NUMPAD8:
372         case WXK_NUMPAD9:
373             ch = (wxChar)(_T('0') + keycode - WXK_NUMPAD0);
374             break;
375 
376         case WXK_MULTIPLY:
377         case WXK_NUMPAD_MULTIPLY:
378             ch = _T('*');
379             break;
380 
381         case WXK_ADD:
382         case WXK_NUMPAD_ADD:
383             ch = _T('+');
384             break;
385 
386         case WXK_SUBTRACT:
387         case WXK_NUMPAD_SUBTRACT:
388             ch = _T('-');
389             break;
390 
391         case WXK_DECIMAL:
392         case WXK_NUMPAD_DECIMAL:
393             ch = _T('.');
394             break;
395 
396         case WXK_DIVIDE:
397         case WXK_NUMPAD_DIVIDE:
398             ch = _T('/');
399             break;
400 
401         case WXK_DELETE:
402         case WXK_NUMPAD_DELETE:
403             // delete the character at cursor
404             {
405                 const long pos = GetInsertionPoint();
406                 if ( pos < GetLastPosition() )
407                     Remove(pos, pos + 1);
408             }
409             break;
410 
411         case WXK_BACK:
412             // delete the character before the cursor
413             {
414                 const long pos = GetInsertionPoint();
415                 if ( pos > 0 )
416                     Remove(pos - 1, pos);
417             }
418             break;
419 
420         default:
421 #if wxUSE_UNICODE
422             if ( event.GetUnicodeKey() )
423             {
424                 ch = event.GetUnicodeKey();
425             }
426             else
427 #endif
428             if ( keycode < 256 && keycode >= 0 && wxIsprint(keycode) )
429             {
430                 // FIXME this is not going to work for non letters...
431                 if ( !event.ShiftDown() )
432                 {
433                     keycode = wxTolower(keycode);
434                 }
435 
436                 ch = (wxChar)keycode;
437             }
438             else
439             {
440                 ch = _T('\0');
441             }
442     }
443 
444     if ( ch )
445     {
446         WriteText(ch);
447 
448         return true;
449     }
450 
451     return false;
452 }
453 #endif // !__WIN32__
454 
455 // ----------------------------------------------------------------------------
456 // selection and ranges
457 // ----------------------------------------------------------------------------
458 
SelectAll()459 void wxTextCtrlBase::SelectAll()
460 {
461     SetSelection(0, GetLastPosition());
462 }
463 
GetStringSelection() const464 wxString wxTextCtrlBase::GetStringSelection() const
465 {
466     long from, to;
467     GetSelection(&from, &to);
468 
469     return GetRange(from, to);
470 }
471 
GetRange(long from,long to) const472 wxString wxTextCtrlBase::GetRange(long from, long to) const
473 {
474     wxString sel;
475     if ( from < to )
476     {
477         sel = GetValue().Mid(from, to - from);
478     }
479 
480     return sel;
481 }
482 
483 // do the window-specific processing after processing the update event
DoUpdateWindowUI(wxUpdateUIEvent & event)484 void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
485 {
486     // call inherited, but skip the wxControl's version, and call directly the
487     // wxWindow's one instead, because the only reason why we are overriding this
488     // function is that we want to use SetValue() instead of wxControl::SetLabel()
489     wxWindowBase::DoUpdateWindowUI(event);
490 
491     // update text
492     if ( event.GetSetText() )
493     {
494         if ( event.GetText() != GetValue() )
495             SetValue(event.GetText());
496     }
497 }
498 
499 // ----------------------------------------------------------------------------
500 // hit testing
501 // ----------------------------------------------------------------------------
502 
503 wxTextCtrlHitTestResult
HitTest(const wxPoint & pt,wxTextCoord * x,wxTextCoord * y) const504 wxTextCtrlBase::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const
505 {
506     // implement in terms of the other overload as the native ports typically
507     // can get the position and not (x, y) pair directly (although wxUniv
508     // directly gets x and y -- and so overrides this method as well)
509     long pos;
510     wxTextCtrlHitTestResult rc = HitTest(pt, &pos);
511 
512     if ( rc != wxTE_HT_UNKNOWN )
513     {
514         PositionToXY(pos, x, y);
515     }
516 
517     return rc;
518 }
519 
520 wxTextCtrlHitTestResult
HitTest(const wxPoint & WXUNUSED (pt),long * WXUNUSED (pos)) const521 wxTextCtrlBase::HitTest(const wxPoint& WXUNUSED(pt),
522                         long * WXUNUSED(pos)) const
523 {
524     // not implemented
525     return wxTE_HT_UNKNOWN;
526 }
527 
528 // ----------------------------------------------------------------------------
529 // events
530 // ----------------------------------------------------------------------------
531 
SendTextUpdatedEvent()532 void wxTextCtrlBase::SendTextUpdatedEvent()
533 {
534     wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
535 
536     // do not do this as it could be very inefficient if the text control
537     // contains a lot of text and we're not using ref-counted wxString
538     // implementation -- instead, event.GetString() will query the control for
539     // its current text if needed
540     //event.SetString(GetValue());
541 
542     event.SetEventObject(this);
543     GetEventHandler()->ProcessEvent(event);
544 }
545 
546 #else // !wxUSE_TEXTCTRL
547 
548 // define this one even if !wxUSE_TEXTCTRL because it is also used by other
549 // controls (wxComboBox and wxSpinCtrl)
550 
551 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED)
552 
553 #endif // wxUSE_TEXTCTRL/!wxUSE_TEXTCTRL
554