X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7b235dce88ca7e3fc0182c5b8ce088f1281c3321..035fa7f78c8915a24114d26728fa805773f2c4b5:/src/common/valtext.cpp diff --git a/src/common/valtext.cpp b/src/common/valtext.cpp index 202e8195fa..43c87eb446 100644 --- a/src/common/valtext.cpp +++ b/src/common/valtext.cpp @@ -2,7 +2,7 @@ // Name: src/common/valtext.cpp // Purpose: wxTextValidator // Author: Julian Smart -// Modified by: +// Modified by: Francesco Montorsi // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart @@ -33,28 +33,39 @@ #include #include -#ifdef __SALFORDC__ - #include -#endif +#include "wx/combo.h" -IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) +// ---------------------------------------------------------------------------- +// global helpers +// ---------------------------------------------------------------------------- + +static bool wxIsNumeric(const wxString& val) +{ + for ( wxString::const_iterator i = val.begin(); i != val.end(); ++i ) + { + // Allow for "," (French) as well as "." -- in future we should + // use wxSystemSettings or other to do better localisation + if ((!wxIsdigit(*i)) && + (*i != wxS('.')) && (*i != wxS(',')) && (*i != wxS('e')) && + (*i != wxS('E')) && (*i != wxS('+')) && (*i != wxS('-'))) + return false; + } + return true; +} + +// ---------------------------------------------------------------------------- +// wxTextValidator +// ---------------------------------------------------------------------------- +IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) BEGIN_EVENT_TABLE(wxTextValidator, wxValidator) EVT_CHAR(wxTextValidator::OnChar) END_EVENT_TABLE() -static bool wxIsNumeric(const wxString& val); - wxTextValidator::wxTextValidator(long style, wxString *val) { - m_validatorStyle = style; m_stringValue = val; -/* - m_refData = new wxVTextRefData; - - M_VTEXTDATA->m_validatorStyle = style; - M_VTEXTDATA->m_stringValue = val; -*/ + SetStyle(style); } wxTextValidator::wxTextValidator(const wxTextValidator& val) @@ -63,6 +74,30 @@ wxTextValidator::wxTextValidator(const wxTextValidator& val) Copy(val); } +void wxTextValidator::SetStyle(long style) +{ + m_validatorStyle = style; + +#if wxDEBUG_LEVEL + int check; + check = (int)HasFlag(wxFILTER_ALPHA) + (int)HasFlag(wxFILTER_ALPHANUMERIC) + + (int)HasFlag(wxFILTER_DIGITS) + (int)HasFlag(wxFILTER_NUMERIC); + wxASSERT_MSG(check <= 1, + "It makes sense to use only one of the wxFILTER_ALPHA/wxFILTER_ALPHANUMERIC/" + "wxFILTER_SIMPLE_NUMBER/wxFILTER_NUMERIC styles"); + + wxASSERT_MSG(((int)HasFlag(wxFILTER_INCLUDE_LIST) + (int)HasFlag(wxFILTER_INCLUDE_CHAR_LIST) <= 1) && + ((int)HasFlag(wxFILTER_EXCLUDE_LIST) + (int)HasFlag(wxFILTER_EXCLUDE_CHAR_LIST) <= 1), + "Using both wxFILTER_[IN|EX]CLUDE_LIST _and_ wxFILTER_[IN|EX]CLUDE_CHAR_LIST " + "doesn't work since wxTextValidator internally uses the same array for both"); + + check = (int)HasFlag(wxFILTER_INCLUDE_LIST) + (int)HasFlag(wxFILTER_INCLUDE_CHAR_LIST) + + (int)HasFlag(wxFILTER_EXCLUDE_LIST) + (int)HasFlag(wxFILTER_EXCLUDE_CHAR_LIST); + wxASSERT_MSG(check <= 1, + "Using both an include/exclude list may lead to unexpected results"); +#endif // wxDEBUG_LEVEL +} + bool wxTextValidator::Copy(const wxTextValidator& val) { wxValidator::Copy(val); @@ -85,45 +120,28 @@ wxTextEntry *wxTextValidator::GetTextEntry() } #endif - // FIXME: in wxMotif wxComboBox doesn't derive from wxTextCtrl yet -#ifndef __WXMOTIF__ #if wxUSE_COMBOBOX if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox))) { return (wxComboBox*)m_validatorWindow; } #endif -#endif // !__WXMOTIF__ + +#if wxUSE_COMBOCTRL + if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboCtrl))) + { + return (wxComboCtrl*)m_validatorWindow; + } +#endif wxFAIL_MSG( - _T("wxTextValidator can only be used with wxTextCtrl or wxComboBox") + "wxTextValidator can only be used with wxTextCtrl, wxComboBox, " + "or wxComboCtrl" ); return NULL; } -static bool wxIsAlpha(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - if (!wxIsalpha(val[i])) - return false; - } - return true; -} - -static bool wxIsAlphaNumeric(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - if (!wxIsalnum(val[i])) - return false; - } - return true; -} - // Called when the value in the window must be validated. // This function can pop up an error message. bool wxTextValidator::Validate(wxWindow *parent) @@ -138,77 +156,33 @@ bool wxTextValidator::Validate(wxWindow *parent) wxString val(text->GetValue()); - bool ok = true; - - // NB: this format string should contian exactly one '%s' wxString errormsg; - - bool includes = (m_validatorStyle & wxFILTER_INCLUDE_LIST) != 0; - if ( includes || (m_validatorStyle & wxFILTER_EXCLUDE_LIST) ) - { - // if includes, it's only ok to have the members of the list, - // otherwise it's only ok to have non-members - ok = includes == (m_includes.Index(val) != wxNOT_FOUND); - if ( !ok ) - { - errormsg = _("'%s' is invalid"); - } - } - else if ( (m_validatorStyle & wxFILTER_ASCII) && !val.IsAscii() ) - { - ok = false; - - errormsg = _("'%s' should only contain ASCII characters."); - } - else if ( (m_validatorStyle & wxFILTER_ALPHA) && !wxIsAlpha(val) ) - { - ok = false; - - errormsg = _("'%s' should only contain alphabetic characters."); - } - else if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsAlphaNumeric(val)) - { - ok = false; - - errormsg = _("'%s' should only contain alphabetic or numeric characters."); - } - else if ( (m_validatorStyle & wxFILTER_NUMERIC) && !wxIsNumeric(val)) - { - ok = false; - - errormsg = _("'%s' should be numeric."); - } - else if ( (m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(val)) + if ( HasFlag(wxFILTER_EMPTY) && val.empty() ) { - //it's only ok to have the members of the list - errormsg = _("'%s' is invalid"); - ok = false; + errormsg = _("Required information entry is empty."); } - else if ( (m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(val)) + else if ( !(errormsg = IsValid(val)).empty() ) { - // it's only ok to have non-members of the list - errormsg = _("'%s' is invalid"); - ok = false; + // NB: this format string should always contain exactly one '%s' + wxString buf; + buf.Printf(errormsg, val.c_str()); + errormsg = buf; } - if ( !ok ) + if ( !errormsg.empty() ) { - wxASSERT_MSG( !errormsg.empty(), _T("you forgot to set errormsg") ); - m_validatorWindow->SetFocus(); - - wxString buf; - buf.Printf(errormsg, val.c_str()); - - wxMessageBox(buf, _("Validation conflict"), + wxMessageBox(errormsg, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); + + return false; } - return ok; + return true; } // Called to transfer data to the window -bool wxTextValidator::TransferToWindow(void) +bool wxTextValidator::TransferToWindow() { if ( m_stringValue ) { @@ -223,7 +197,7 @@ bool wxTextValidator::TransferToWindow(void) } // Called to transfer data to the window -bool wxTextValidator::TransferFromWindow(void) +bool wxTextValidator::TransferFromWindow() { if ( m_stringValue ) { @@ -237,75 +211,123 @@ bool wxTextValidator::TransferFromWindow(void) return true; } -bool wxTextValidator::IsInCharIncludes(const wxString& val) +// IRIX mipsPro refuses to compile wxStringCheck() if func is inline so +// let's work around this by using this non-template function instead of +// wxStringCheck(). And while this might be fractionally less efficient because +// the function call won't be inlined like this, we don't care enough about +// this to add extra #ifs for non-IRIX case. +namespace +{ + +bool CheckString(bool (*func)(const wxUniChar&), const wxString& str) { - size_t i; - for ( i = 0; i < val.length(); i++) + for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i ) { - if (m_includes.Index((wxString) val[i]) == wxNOT_FOUND) + if ( !func(*i) ) return false; } + return true; } -bool wxTextValidator::IsNotInCharExcludes(const wxString& val) +} // anonymous namespace + +wxString wxTextValidator::IsValid(const wxString& val) const { - size_t i; - for ( i = 0; i < val.length(); i++) - { - if (m_excludes.Index((wxString) val[i]) != wxNOT_FOUND) + // wxFILTER_EMPTY is checked for in wxTextValidator::Validate + + if ( HasFlag(wxFILTER_ASCII) && !val.IsAscii() ) + return _("'%s' should only contain ASCII characters."); + if ( HasFlag(wxFILTER_ALPHA) && !CheckString(wxIsalpha, val) ) + return _("'%s' should only contain alphabetic characters."); + if ( HasFlag(wxFILTER_ALPHANUMERIC) && !CheckString(wxIsalnum, val) ) + return _("'%s' should only contain alphabetic or numeric characters."); + if ( HasFlag(wxFILTER_DIGITS) && !CheckString(wxIsdigit, val) ) + return _("'%s' should only contain digits."); + if ( HasFlag(wxFILTER_NUMERIC) && !wxIsNumeric(val) ) + return _("'%s' should be numeric."); + if ( HasFlag(wxFILTER_INCLUDE_LIST) && m_includes.Index(val) == wxNOT_FOUND ) + return _("'%s' is invalid"); + if ( HasFlag(wxFILTER_INCLUDE_CHAR_LIST) && !ContainsOnlyIncludedCharacters(val) ) + return _("'%s' is invalid"); + if ( HasFlag(wxFILTER_EXCLUDE_LIST) && m_excludes.Index(val) != wxNOT_FOUND ) + return _("'%s' is invalid"); + if ( HasFlag(wxFILTER_EXCLUDE_CHAR_LIST) && ContainsExcludedCharacters(val) ) + return _("'%s' is invalid"); + + return wxEmptyString; +} + +bool wxTextValidator::ContainsOnlyIncludedCharacters(const wxString& val) const +{ + for ( wxString::const_iterator i = val.begin(); i != val.end(); ++i ) + if (m_includes.Index((wxString) *i) == wxNOT_FOUND) + // one character of 'val' is NOT present in m_includes... return false; - } + + // all characters of 'val' are present in m_includes return true; } +bool wxTextValidator::ContainsExcludedCharacters(const wxString& val) const +{ + for ( wxString::const_iterator i = val.begin(); i != val.end(); ++i ) + if (m_excludes.Index((wxString) *i) != wxNOT_FOUND) + // one character of 'val' is present in m_excludes... + return true; + + // all characters of 'val' are NOT present in m_excludes + return false; +} + +void wxTextValidator::SetCharIncludes(const wxString& chars) +{ + wxArrayString arr; + + for ( wxString::const_iterator i = chars.begin(); i != chars.end(); ++i ) + arr.Add(*i); + + SetIncludes(arr); +} + +void wxTextValidator::SetCharExcludes(const wxString& chars) +{ + wxArrayString arr; + + for ( wxString::const_iterator i = chars.begin(); i != chars.end(); ++i ) + arr.Add(*i); + + SetExcludes(arr); +} + void wxTextValidator::OnChar(wxKeyEvent& event) { -/* - if ( !M_VTEXTDATA ) + if (!m_validatorWindow) + { + event.Skip(); return; -*/ + } + + int keyCode = event.GetKeyCode(); - if ( m_validatorWindow ) + // we don't filter special keys and delete + if (keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode >= WXK_START) { - int keyCode = event.GetKeyCode(); - - // we don't filter special keys and Delete - if ( - !(keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode > WXK_START) && - ( - ((m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(wxString((wxChar) keyCode, 1))) || - ((m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(wxString((wxChar) keyCode, 1))) || - ((m_validatorStyle & wxFILTER_ASCII) && !isascii(keyCode)) || - ((m_validatorStyle & wxFILTER_ALPHA) && !wxIsalpha(keyCode)) || - ((m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsalnum(keyCode)) || - ((m_validatorStyle & wxFILTER_NUMERIC) && !wxIsdigit(keyCode) - && keyCode != wxT('.') && keyCode != wxT(',') && keyCode != wxT('-') && keyCode != wxT('+') && keyCode != wxT('e') && keyCode != wxT('E')) - ) - ) - { - if ( !wxValidator::IsSilent() ) - wxBell(); - - // eat message - return; - } + event.Skip(); + return; } - event.Skip(); -} - -static bool wxIsNumeric(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) + wxString str((wxUniChar)keyCode, 1); + if (!IsValid(str).empty()) { - // Allow for "," (French) as well as "." -- in future we should - // use wxSystemSettings or other to do better localisation - if ((!wxIsdigit(val[i])) && (val[i] != wxT('.')) && (val[i] != wxT(',')) && (val[i] != wxT('e')) && (val[i] != wxT('E')) && (val[i] != wxT('+')) && (val[i] != wxT('-'))) - return false; + if ( !wxValidator::IsSilent() ) + wxBell(); + + // eat message + return; } - return true; + else + event.Skip(); }