X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0ded21d1a195eabfd65e6ae20651a081195eb697..0f5378d414cb68caaa535199c1af12dec1720c3d:/src/common/valtext.cpp?ds=inline diff --git a/src/common/valtext.cpp b/src/common/valtext.cpp index 299ef6042a..dced8ecb83 100644 --- a/src/common/valtext.cpp +++ b/src/common/valtext.cpp @@ -1,317 +1,335 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: valtext.cpp +// 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 and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "valtext.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif -#ifndef WX_PRECOMP -#include -#include "wx/textctrl.h" -#include "wx/utils.h" -#include "wx/msgdlg.h" -#include "wx/intl.h" -#endif +#if wxUSE_VALIDATORS && (wxUSE_TEXTCTRL || wxUSE_COMBOBOX) #include "wx/valtext.h" +#ifndef WX_PRECOMP + #include + #include "wx/textctrl.h" + #include "wx/combobox.h" + #include "wx/utils.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" +#endif + #include #include #include -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) +#include "wx/combo.h" + +// ---------------------------------------------------------------------------- +// 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) + EVT_CHAR(wxTextValidator::OnChar) END_EVENT_TABLE() -#endif - -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 ; -*/ + m_stringValue = val; + SetStyle(style); } wxTextValidator::wxTextValidator(const wxTextValidator& val) + : wxValidator() { 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); - m_validatorStyle = val.m_validatorStyle ; - m_stringValue = val.m_stringValue ; - - wxNode *node = val.m_includeList.First() ; - while ( node ) - { - char *s = (char *)node->Data(); - m_includeList.Add(s); - node = node->Next(); - } - node = val.m_excludeList.First() ; - while ( node ) - { - char *s = (char *)node->Data(); - m_excludeList.Add(s); - node = node->Next(); - } - return TRUE; -} + m_validatorStyle = val.m_validatorStyle; + m_stringValue = val.m_stringValue; -wxTextValidator::~wxTextValidator() -{ -} + m_includes = val.m_includes; + m_excludes = val.m_excludes; -static bool wxIsAlpha(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.Length(); i++) - { - if (!isalpha(val[i])) - return FALSE; - } - return TRUE; + return true; } -static bool wxIsAlphaNumeric(const wxString& val) +wxTextEntry *wxTextValidator::GetTextEntry() { - int i; - for ( i = 0; i < (int)val.Length(); i++) - { - if (!isalnum(val[i])) - return FALSE; - } - return TRUE; +#if wxUSE_TEXTCTRL + if (wxDynamicCast(m_validatorWindow, wxTextCtrl)) + { + return (wxTextCtrl*)m_validatorWindow; + } +#endif + +#if wxUSE_COMBOBOX + if (wxDynamicCast(m_validatorWindow, wxComboBox)) + { + return (wxComboBox*)m_validatorWindow; + } +#endif + +#if wxUSE_COMBOCTRL + if (wxDynamicCast(m_validatorWindow, wxComboCtrl)) + { + return (wxComboCtrl*)m_validatorWindow; + } +#endif + + wxFAIL_MSG( + "wxTextValidator can only be used with wxTextCtrl, wxComboBox, " + "or wxComboCtrl" + ); + + return NULL; } // Called when the value in the window must be validated. // This function can pop up an error message. bool wxTextValidator::Validate(wxWindow *parent) { - if ( !m_validatorWindow ) - return FALSE; - if ( !m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - return FALSE; - if ( !m_stringValue ) - return FALSE; - - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow ; - - // If window is disabled, don't validate - if ( !control->Enabled() ) - return FALSE; - - wxString val(control->GetValue()); - - if ( m_validatorStyle & wxFILTER_INCLUDE_LIST ) - { - if ( !m_includeList.Member(val) ) - { - m_validatorWindow->SetFocus(); - char buf[512]; - sprintf(buf, _("%s is invalid."), (const char *)val); - wxMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); - return FALSE; - } - } - if ( m_validatorStyle & wxFILTER_EXCLUDE_LIST ) - { - if ( m_excludeList.Member(val) ) - { - m_validatorWindow->SetFocus(); - char buf[512]; - sprintf(buf, _("%s is invalid."), (const char *)val); - wxMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); - return FALSE; - } - } - if ( (m_validatorStyle & wxFILTER_ASCII) && !val.IsAscii() ) - { - m_validatorWindow->SetFocus(); - char buf[512]; - sprintf(buf, _("%s should only contain ASCII characters."), (const char *)val); - wxMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); - return FALSE; - } - if ( (m_validatorStyle & wxFILTER_ALPHA) && !wxIsAlpha(val) ) - { - m_validatorWindow->SetFocus(); - char buf[512]; - sprintf(buf, _("%s should only contain alphabetic characters."), (const char *)val); - wxMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); - return FALSE; - } - if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsAlphaNumeric(val)) - { - m_validatorWindow->SetFocus(); - char buf[512]; - sprintf(buf, _("%s should only contain alphabetic or numeric characters."), (const char *)val); - wxMessageBox(buf,_("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); - return FALSE; - } - if ( (m_validatorStyle & wxFILTER_NUMERIC) && !wxIsNumeric(val)) - - { - m_validatorWindow->SetFocus(); - char buf[512]; - sprintf(buf, _("%s should be numeric."), (const char *)val); - wxMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent); - return FALSE; - } - - return TRUE ; + // If window is disabled, simply return + if ( !m_validatorWindow->IsEnabled() ) + return true; + + wxTextEntry * const text = GetTextEntry(); + if ( !text ) + return false; + + wxString val(text->GetValue()); + + wxString errormsg; + if ( HasFlag(wxFILTER_EMPTY) && val.empty() ) + { + errormsg = _("Required information entry is empty."); + } + else if ( !(errormsg = IsValid(val)).empty() ) + { + // NB: this format string should always contain exactly one '%s' + wxString buf; + buf.Printf(errormsg, val.c_str()); + errormsg = buf; + } + + if ( !errormsg.empty() ) + { + m_validatorWindow->SetFocus(); + wxMessageBox(errormsg, _("Validation conflict"), + wxOK | wxICON_EXCLAMATION, parent); + + return false; + } + + return true; } // Called to transfer data to the window -bool wxTextValidator::TransferToWindow(void) +bool wxTextValidator::TransferToWindow() { - if ( !m_validatorWindow ) - return FALSE; - if ( !m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - return FALSE; - if ( !m_stringValue ) - return FALSE; + if ( m_stringValue ) + { + wxTextEntry * const text = GetTextEntry(); + if ( !text ) + return false; - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow ; - control->SetValue(* m_stringValue) ; + text->SetValue(*m_stringValue); + } - return TRUE; + return true; } // Called to transfer data to the window -bool wxTextValidator::TransferFromWindow(void) +bool wxTextValidator::TransferFromWindow() { - if ( !m_validatorWindow ) - return FALSE; - if ( !m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - return FALSE; - if ( !m_stringValue ) - return FALSE; + if ( m_stringValue ) + { + wxTextEntry * const text = GetTextEntry(); + if ( !text ) + return false; - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow ; - * m_stringValue = control->GetValue() ; + *m_stringValue = text->GetValue(); + } - return TRUE; + return true; } -void wxTextValidator::SetIncludeList(const wxStringList& list) +// 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 { -/* - if ( !M_VTEXTDATA ) - return; -*/ - - m_includeList.Clear(); - // TODO: replace with = - wxNode *node = list.First() ; - while ( node ) - { - char *s = (char *)node->Data(); - m_includeList.Add(s); - node = node->Next(); - } + +bool CheckString(bool (*func)(const wxUniChar&), const wxString& str) +{ + for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i ) + { + if ( !func(*i) ) + return false; + } + + return true; } -void wxTextValidator::SetExcludeList(const wxStringList& list) +} // anonymous namespace + +wxString wxTextValidator::IsValid(const wxString& val) const { -/* - if ( !M_VTEXTDATA ) - return; -*/ - - m_excludeList.Clear(); - // TODO: replace with = - wxNode *node = list.First() ; - while ( node ) - { - char *s = (char *)node->Data(); - m_excludeList.Add(s); - node = node->Next(); - } + // 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; } -void wxTextValidator::OnChar(wxKeyEvent& event) +bool wxTextValidator::ContainsOnlyIncludedCharacters(const wxString& val) const { -/* - if ( !M_VTEXTDATA ) - return; -*/ - - if ( !m_validatorWindow ) - return; - - wxTextCtrl *textCtrl = (wxTextCtrl *)m_validatorWindow; - - int keyCode = event.KeyCode(); - if (keyCode == WXK_DELETE || keyCode == WXK_RETURN || keyCode == WXK_BACK || - keyCode == WXK_HOME || keyCode == WXK_LEFT || keyCode == WXK_UP || - keyCode == WXK_RIGHT || keyCode == WXK_DOWN || keyCode == WXK_PRIOR || - keyCode == WXK_NEXT || keyCode == WXK_END || keyCode == WXK_HOME) - { - textCtrl->wxTextCtrl::OnChar(event); - return ; - } - - if ( (m_validatorStyle & wxFILTER_ASCII) && !isascii(keyCode) ) - { - wxBell(); - return; - } - if ( (m_validatorStyle & wxFILTER_ALPHA) && !isalpha(keyCode) ) - { - wxBell(); - return; - } - if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !isalnum(keyCode) ) - { - wxBell(); - return; - } - if ( (m_validatorStyle & wxFILTER_NUMERIC) && !isdigit(keyCode) && keyCode != '.' && keyCode != '-') - { - wxBell(); - return; - } - - textCtrl->wxTextCtrl::OnChar(event); + 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; } -static bool wxIsNumeric(const wxString& val) +bool wxTextValidator::ContainsExcludedCharacters(const wxString& val) const { - int i; - for ( i = 0; i < (int)val.Length(); i++) - { - if ((!isdigit(val[i])) && (val[i] != '.')) - if(!((i == 0) && (val[i] == '-'))) - return FALSE; - } - return TRUE; + 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_validatorWindow) + { + event.Skip(); + return; + } + + int keyCode = event.GetKeyCode(); + + // we don't filter special keys and delete + if (keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode >= WXK_START) + { + event.Skip(); + return; + } + + wxString str((wxUniChar)keyCode, 1); + if (!IsValid(str).empty()) + { + if ( !wxValidator::IsSilent() ) + wxBell(); + + // eat message + return; + } + else + event.Skip(); +} + + +#endif + // wxUSE_VALIDATORS && (wxUSE_TEXTCTRL || wxUSE_COMBOBOX)