wxTextValidator improvements

Improve char inclusion/exclusion support; update the sample to show more
features of this class and add a unit test for it.

Closes https://github.com/wxWidgets/wxWidgets/pull/1093
This commit is contained in:
ali kettab
2019-01-01 00:55:14 +01:00
committed by Vadim Zeitlin
parent 697125dc03
commit 36f6f8ad49
18 changed files with 1000 additions and 247 deletions

View File

@@ -104,6 +104,10 @@ Changes in behaviour which may result in build errors
e.g. if the error is due to spelling an option name wrongly, fixing or e.g. if the error is due to spelling an option name wrongly, fixing or
removing its name. removing its name.
- wxTextValidator::Get{In,Ex}cludes() now return a const reference to
wxArrayString. Please update your code to use the appropriate setter
Set[Char]{In,Ex}cludes(), instead of mutating the internal data directly.
3.1.3: (released 2019-??-??) 3.1.3: (released 2019-??-??)
---------------------------- ----------------------------

View File

@@ -31,9 +31,20 @@ enum wxTextValidatorStyle
wxFILTER_INCLUDE_LIST = 0x40, wxFILTER_INCLUDE_LIST = 0x40,
wxFILTER_INCLUDE_CHAR_LIST = 0x80, wxFILTER_INCLUDE_CHAR_LIST = 0x80,
wxFILTER_EXCLUDE_LIST = 0x100, wxFILTER_EXCLUDE_LIST = 0x100,
wxFILTER_EXCLUDE_CHAR_LIST = 0x200 wxFILTER_EXCLUDE_CHAR_LIST = 0x200,
wxFILTER_XDIGITS = 0x400,
wxFILTER_SPACE = 0x800,
// filter char class (for internal use only)
wxFILTER_CC = wxFILTER_SPACE|wxFILTER_ASCII|wxFILTER_NUMERIC|
wxFILTER_ALPHANUMERIC|wxFILTER_ALPHA|
wxFILTER_DIGITS|wxFILTER_XDIGITS
}; };
// ----------------------------------------------------------------------------
// wxTextValidator
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxTextValidator: public wxValidator class WXDLLIMPEXP_CORE wxTextValidator: public wxValidator
{ {
public: public:
@@ -68,31 +79,78 @@ public:
wxTextEntry *GetTextEntry(); wxTextEntry *GetTextEntry();
// strings & chars inclusions:
// ---------------------------
void SetCharIncludes(const wxString& chars); void SetCharIncludes(const wxString& chars);
void SetIncludes(const wxArrayString& includes) { m_includes = includes; } void AddCharIncludes(const wxString& chars);
inline wxArrayString& GetIncludes() { return m_includes; }
void SetIncludes(const wxArrayString& includes);
void AddInclude(const wxString& include);
const wxArrayString& GetIncludes() const { return m_includes; }
wxString GetCharIncludes() const { return m_charIncludes; }
// strings & chars exclusions:
// ---------------------------
void SetCharExcludes(const wxString& chars); void SetCharExcludes(const wxString& chars);
void SetExcludes(const wxArrayString& excludes) { m_excludes = excludes; } void AddCharExcludes(const wxString& chars);
inline wxArrayString& GetExcludes() { return m_excludes; }
void SetExcludes(const wxArrayString& excludes);
void AddExclude(const wxString& exclude);
const wxArrayString& GetExcludes() const { return m_excludes; }
wxString GetCharExcludes() const { return m_charExcludes; }
bool HasFlag(wxTextValidatorStyle style) const bool HasFlag(wxTextValidatorStyle style) const
{ return (m_validatorStyle & style) != 0; } { return (m_validatorStyle & style) != 0; }
// implementation only
// --------------------
// returns the error message if the contents of 'str' are invalid
virtual wxString IsValid(const wxString& str) const;
protected: protected:
// returns true if all characters of the given string are present in m_includes bool IsCharIncluded(const wxUniChar& c) const
{
return m_charIncludes.find(c) != wxString::npos;
}
bool IsCharExcluded(const wxUniChar& c) const
{
return m_charExcludes.find(c) != wxString::npos;
}
bool IsIncluded(const wxString& str) const
{
if ( HasFlag(wxFILTER_INCLUDE_LIST) )
return m_includes.Index(str) != wxNOT_FOUND;
// m_includes should be ignored (i.e. return true)
// if the style is not set.
return true;
}
bool IsExcluded(const wxString& str) const
{
return m_excludes.Index(str) != wxNOT_FOUND;
}
// returns false if the character is invalid
bool IsValidChar(const wxUniChar& c) const;
// These two functions (undocumented now) are kept for compatibility reasons.
bool ContainsOnlyIncludedCharacters(const wxString& val) const; bool ContainsOnlyIncludedCharacters(const wxString& val) const;
// returns true if at least one character of the given string is present in m_excludes
bool ContainsExcludedCharacters(const wxString& val) const; bool ContainsExcludedCharacters(const wxString& val) const;
// returns the error message if the contents of 'val' are invalid
virtual wxString IsValid(const wxString& val) const;
protected: protected:
long m_validatorStyle; long m_validatorStyle;
wxString* m_stringValue; wxString* m_stringValue;
wxString m_charIncludes;
wxString m_charExcludes;
wxArrayString m_includes; wxArrayString m_includes;
wxArrayString m_excludes; wxArrayString m_excludes;

View File

@@ -9,8 +9,11 @@
/** /**
Styles used by wxTextValidator. Styles used by wxTextValidator.
Note that when you specify more styles in wxTextValidator the validation checks Notice that wxFILTER_EXCLUDE[_CHAR]_LIST pair can be used to document the
are performed in the order in which the styles of this enumeration are defined. purpose of the validator only and are not enforced in the implementation of
the wxTextValidator. Therefore, calling the corresponding member functions:
wxTextValidator::{SetExcludes,SetCharExcludes}(), is enough to create the
desired validator.
*/ */
enum wxTextValidatorStyle enum wxTextValidatorStyle
{ {
@@ -33,9 +36,11 @@ enum wxTextValidatorStyle
/// Non-alphanumeric characters are filtered out. /// Non-alphanumeric characters are filtered out.
/// Uses the wxWidgets wrapper for the standard CRT function @c isalnum /// Uses the wxWidgets wrapper for the standard CRT function @c isalnum
/// (which is locale-dependent) on all characters of the string. /// (which is locale-dependent) on all characters of the string.
/// Equivalent to wxFILTER_ALPHA combined with wxFILTER_DIGITS or
/// wxFILTER_XDIGITS, or with both of them.
wxFILTER_ALPHANUMERIC, wxFILTER_ALPHANUMERIC,
/// Non-numeric characters are filtered out. /// Non-digit characters are filtered out.
/// Uses the wxWidgets wrapper for the standard CRT function @c isdigit /// Uses the wxWidgets wrapper for the standard CRT function @c isdigit
/// (which is locale-dependent) on all characters of the string. /// (which is locale-dependent) on all characters of the string.
wxFILTER_DIGITS, wxFILTER_DIGITS,
@@ -50,19 +55,36 @@ enum wxTextValidatorStyle
/// the list, complaining if not. See wxTextValidator::SetIncludes(). /// the list, complaining if not. See wxTextValidator::SetIncludes().
wxFILTER_INCLUDE_LIST, wxFILTER_INCLUDE_LIST,
/// Use an include list. The validator checks if each input character is /// Use an include char list.
/// in the list (one character per list element), complaining if not. /// Characters in the include char list will be allowed to be in the
/// See wxTextValidator::SetCharIncludes(). /// user input. See wxTextValidator::SetCharIncludes().
/// If this style is set with one or more of the following styles:
/// wxFILTER_ASCII, wxFILTER_ALPHA, wxFILTER_ALPHANUMERIC, wxFILTER_DIGITS,
/// wxFILTER_XDIGITS, wxFILTER_NUMERIC it just extends the character class
/// denoted by the aforementioned styles with those specified in the include
/// char list. If set alone, then the charactes allowed to be in the user input
/// are restricted to those, and only those, present in the include char list.
wxFILTER_INCLUDE_CHAR_LIST, wxFILTER_INCLUDE_CHAR_LIST,
/// Use an exclude list. The validator checks if the user input is on /// Use an exclude list. The validator checks if the user input is on
/// the list, complaining if it is. See wxTextValidator::SetExcludes(). /// the list, complaining if it is. See wxTextValidator::SetExcludes().
wxFILTER_EXCLUDE_LIST, wxFILTER_EXCLUDE_LIST,
/// Use an exclude list. The validator checks if each input character is /// Use an exclude char list.
/// in the list (one character per list element), complaining if it is. /// Characters in the exclude char list won't be allowed to be in the
/// See wxTextValidator::SetCharExcludes(). /// user input. See wxTextValidator::SetCharExcludes().
wxFILTER_EXCLUDE_CHAR_LIST wxFILTER_EXCLUDE_CHAR_LIST,
/// Non-hexadecimal characters are filtered out.
/// Uses the wxWidgets wrapper for the standard CRT function @c isxdigit
/// (which is locale-dependent) on all characters of the string.
wxFILTER_XDIGITS,
/// A convenience flag for use with the other flags.
/// The space character is more often used with alphanumeric characters
/// which makes setting a flag more easier than calling SetCharIncludes(" ")
/// for that matter.
wxFILTER_SPACE
}; };
/** /**
@@ -83,7 +105,7 @@ class wxTextValidator : public wxValidator
{ {
public: public:
/** /**
Default constructor. Copy constructor.
*/ */
wxTextValidator(const wxTextValidator& validator); wxTextValidator(const wxTextValidator& validator);
@@ -106,14 +128,28 @@ public:
virtual wxObject* Clone() const; virtual wxObject* Clone() const;
/** /**
Returns a reference to the exclude list (the list of invalid values). Returns a copy of the exclude char list (the list of invalid characters).
@since 3.1.3
*/ */
wxArrayString& GetExcludes(); wxString GetCharExcludes() const;
/** /**
Returns a reference to the include list (the list of valid values). Returns a copy of the include char list (the list of additional valid characters).
@since 3.1.3
*/ */
wxArrayString& GetIncludes(); wxString GetCharIncludes() const;
/**
Returns a const reference to the exclude list (the list of invalid values).
*/
const wxArrayString& GetExcludes() const;
/**
Returns a const reference to the include list (the list of valid values).
*/
const wxArrayString& GetIncludes() const;
/** /**
Returns the validator style. Returns the validator style.
@@ -135,41 +171,81 @@ public:
/** /**
Sets the exclude list (invalid values for the user input). Sets the exclude list (invalid values for the user input).
@note Beware that exclusion takes priority over inclusion.
*/ */
void SetExcludes(const wxArrayString& stringList); void SetExcludes(const wxArrayString& stringList);
/** /**
Breaks the given @a chars strings in single characters and sets the Sets the exclude char list (invalid characters for the user input).
internal wxArrayString used to store the "excluded" characters
(see SetExcludes()).
This function is mostly useful when @c wxFILTER_EXCLUDE_CHAR_LIST was used. @note Beware that exclusion takes priority over inclusion.
@note This function may cancel the effect of @c wxFILTER_SPACE if the passed
in string @a chars contains the @b space character.
*/ */
void SetCharExcludes(const wxString& chars); void SetCharExcludes(const wxString& chars);
/** /**
Sets the include list (valid values for the user input). Sets the include list (valid values for the user input).
@see IsIncluded()
*/ */
void SetIncludes(const wxArrayString& stringList); void SetIncludes(const wxArrayString& stringList);
/** /**
Breaks the given @a chars strings in single characters and sets the Sets the include char list (additional valid values for the user input).
internal wxArrayString used to store the "included" characters
(see SetIncludes()).
This function is mostly useful when @c wxFILTER_INCLUDE_CHAR_LIST was used. @note Any explicitly excluded characters will still be excluded even if
they're part of @a chars.
*/ */
void SetCharIncludes(const wxString& chars); void SetCharIncludes(const wxString& chars);
/**
Adds @a exclude to the list of excluded values.
@note Beware that exclusion takes priority over inclusion.
@since 3.1.3
*/
void AddExclude(const wxString& exclude);
/**
Adds @a include to the list of included values.
@note Any explicitly excluded characters will still be excluded.
@since 3.1.3
*/
void AddInclude(const wxString& include);
/**
Adds @a chars to the list of excluded characters.
@note Beware that exclusion takes priority over inclusion.
@since 3.1.3
*/
void AddCharExcludes(const wxString& chars);
/**
Adds @a chars to the list of included characters.
@note Any explicitly excluded characters will still be excluded even if
they're part of @a chars.
@since 3.1.3
*/
void AddCharIncludes(const wxString& chars);
/** /**
Sets the validator style which must be a combination of one or more Sets the validator style which must be a combination of one or more
of the ::wxTextValidatorStyle values. of the ::wxTextValidatorStyle values.
Note that not all possible combinations make sense! Note that not all possible combinations make sense! Also, some
Also note that the order in which the checks are performed is important, combinations have shorter and more idiomatic alternative, e.g.
in case you specify more than a single style. @c wxFILTER_ALPHANUMERIC can be used instead of
wxTextValidator will perform the checks in the same definition order @c wxFILTER_ALPHA|wxFILTER_DIGITS.
used in the ::wxTextValidatorStyle enumeration.
*/ */
void SetStyle(long style); void SetStyle(long style);
@@ -189,24 +265,52 @@ public:
*/ */
virtual bool Validate(wxWindow* parent); virtual bool Validate(wxWindow* parent);
protected:
/**
Returns @true if all the characters of the given @a val string
are present in the include list (set by SetIncludes() or SetCharIncludes()).
*/
bool ContainsOnlyIncludedCharacters(const wxString& val) const;
/**
Returns true if at least one character of the given @a val string
is present in the exclude list (set by SetExcludes() or SetCharExcludes()).
*/
bool ContainsExcludedCharacters(const wxString& val) const;
/** /**
Returns the error message if the contents of @a val are invalid Returns the error message if the contents of @a val are invalid
or the empty string if @a val is valid. or the empty string if @a val is valid.
*/ */
virtual wxString IsValid(const wxString& val) const; virtual wxString IsValid(const wxString& val) const;
protected:
/**
Returns @true if the char @a c is allowed to be in the user input string.
Additional characters, set by SetCharIncludes() or AddCharIncludes() are
also considered.
@since 3.1.3
*/
bool IsCharIncluded(const wxUniChar& c) const;
/**
Returns @true if the char @a c is not allowed to be in the user input string.
(characters set by SetCharExcludes() or AddCharExcludes()).
@since 3.1.3
*/
bool IsCharExcluded(const wxUniChar& c) const;
/**
Returns @true if the string @a str is one of the includes strings set by
SetIncludes() or AddInclude().
Notice that unless wxFILTER_INCLUDE_LIST is specified (in which case the
validator will complain if the user input is not on the list), the list
will be ignored and won't participate in the validation process.
@since 3.1.3
*/
bool IsIncluded(const wxString& str) const;
/**
Returns @true if the string @a str is one of the excludes strings set by
SetExcludes() or AddExclude().
@since 3.1.3
*/
bool IsExcluded(const wxString& str) const;
/// Returns false if the character @a c is invalid.
bool IsValidChar(const wxUniChar& c) const;
}; };

View File

@@ -650,16 +650,12 @@ wxValidator* wxArrayDoubleProperty::DoGetValidator() const
#if wxUSE_VALIDATORS #if wxUSE_VALIDATORS
WX_PG_DOGETVALIDATOR_ENTRY() WX_PG_DOGETVALIDATOR_ENTRY()
wxTextValidator* validator = new wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST); wxTextValidator* validator =
new wxNumericPropertyValidator(wxNumericPropertyValidator::Float);
// Accept characters for numeric elements
wxNumericPropertyValidator numValidator(wxNumericPropertyValidator::Float);
wxArrayString incChars(numValidator.GetIncludes());
// Accept also a delimiter and space character // Accept also a delimiter and space character
incChars.Add(m_delimiter); validator->AddCharIncludes(m_delimiter);
incChars.Add(" "); validator->AddCharIncludes(" ");
validator->SetIncludes(incChars);
WX_PG_DOGETVALIDATOR_EXIT(validator) WX_PG_DOGETVALIDATOR_EXIT(validator)
#else #else

View File

@@ -40,8 +40,6 @@
// Global data // Global data
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
MyData g_data;
wxString g_listbox_choices[] = wxString g_listbox_choices[] =
{"one", "two", "three"}; {"one", "two", "three"};
@@ -51,6 +49,8 @@ wxString g_combobox_choices[] =
wxString g_radiobox_choices[] = wxString g_radiobox_choices[] =
{"green", "yellow", "red"}; {"green", "yellow", "red"};
MyData g_data;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// MyData // MyData
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -63,6 +63,7 @@ MyData::MyData()
m_string = "Spaces are invalid here"; m_string = "Spaces are invalid here";
m_string2 = "Valid text"; m_string2 = "Valid text";
m_listbox_choices.Add(0); m_listbox_choices.Add(0);
m_combobox_choice = g_combobox_choices[0];
m_intValue = 0; m_intValue = 0;
m_smallIntValue = 3; m_smallIntValue = 3;
m_doubleValue = 12354.31; m_doubleValue = 12354.31;
@@ -247,28 +248,19 @@ MyDialog::MyDialog( wxWindow *parent, const wxString& title,
wxFlexGridSizer *flexgridsizer = new wxFlexGridSizer(3, 2, 5, 5); wxFlexGridSizer *flexgridsizer = new wxFlexGridSizer(3, 2, 5, 5);
// Create and add controls to sizers. Note that a member variable // Create and add controls to sizers.
// of g_data is bound to each control upon construction. There is
// currently no easy way to substitute a different validator or a
// different transfer variable after a control has been constructed.
// Pointers to some of these controls are saved in member variables // Pointers to some of these controls are saved in member variables
// so that we can use them elsewhere, like this one. // so that we can use them elsewhere, like this one.
m_text = new wxTextCtrl(this, VALIDATE_TEXT, wxEmptyString, m_text = new wxTextCtrl(this, VALIDATE_TEXT);
wxDefaultPosition, wxDefaultSize, 0, m_text->SetToolTip("wxTextValidator not set");
wxTextValidator(wxFILTER_ALPHA, &g_data.m_string)); m_text->SetHint("Enter some text here, please...");
m_text->SetToolTip("uses wxTextValidator with wxFILTER_ALPHA");
flexgridsizer->Add(m_text, 1, wxGROW); flexgridsizer->Add(m_text, 1, wxGROW);
// Make it possible to change the wxTextValidator for m_text at runtime.
// Now set a wxTextValidator with an explicit list of characters NOT allowed: wxButton* const button =
wxTextValidator textVal(wxFILTER_EMPTY|wxFILTER_EXCLUDE_CHAR_LIST, &g_data.m_string2); new wxButton(this, wxID_ANY, "Set new wxTextValidator...");
textVal.SetCharExcludes("bcwyz"); button->Bind(wxEVT_BUTTON, &MyDialog::OnChangeValidator, this);
wxTextCtrl* txt2 = flexgridsizer->Add(button, wxSizerFlags().Center());
new wxTextCtrl(this, VALIDATE_TEXT2, wxEmptyString,
wxDefaultPosition, wxDefaultSize, 0, textVal);
txt2->SetToolTip("uses wxTextValidator with wxFILTER_EMPTY|wxFILTER_EXCLUDE_CHAR_LIST to exclude 'bcwyz'");
flexgridsizer->Add(txt2, 1, wxGROW);
flexgridsizer->Add(new wxListBox((wxWindow*)this, VALIDATE_LIST, flexgridsizer->Add(new wxListBox((wxWindow*)this, VALIDATE_LIST,
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
@@ -391,17 +383,298 @@ MyDialog::MyDialog( wxWindow *parent, const wxString& title,
// make the dialog a bit bigger than its minimal size: // make the dialog a bit bigger than its minimal size:
SetSize(GetBestSize()*1.5); SetSize(GetBestSize()*1.5);
}
bool MyDialog::TransferDataToWindow() // Now sets the focus to m_text
{
bool r = wxDialog::TransferDataToWindow();
// These function calls have to be made here, after the
// dialog has been created.
m_text->SetFocus(); m_text->SetFocus();
m_combobox->SetSelection(0);
return r;
} }
void MyDialog::OnChangeValidator(wxCommandEvent& WXUNUSED(event))
{
TextValidatorDialog dialog(this, m_text);
if ( dialog.ShowModal() == wxID_OK )
{
dialog.ApplyValidator();
}
}
// ----------------------------------------------------------------------------
// TextValidatorDialog
// ----------------------------------------------------------------------------
TextValidatorDialog::TextValidatorDialog(wxWindow *parent, wxTextCtrl* txtCtrl)
: wxDialog(parent, wxID_ANY, "wxTextValidator Dialog"),
m_txtCtrl(txtCtrl),
m_noValidation(true),
m_validatorStyle(wxFILTER_NONE)
{
if ( m_txtCtrl )
{
wxTextValidator* txtValidator =
wxDynamicCast(m_txtCtrl->GetValidator(), wxTextValidator);
if ( txtValidator )
{
m_validatorStyle = txtValidator->GetStyle();
if ( m_validatorStyle != wxFILTER_NONE )
m_noValidation = false;
m_charIncludes = txtValidator->GetCharIncludes();
m_charExcludes = txtValidator->GetCharExcludes();
m_includes = txtValidator->GetIncludes();
m_excludes = txtValidator->GetExcludes();
}
}
wxFlexGridSizer *fgSizer = new wxFlexGridSizer(2, FromDIP(wxSize(5, 5)));
const wxSizerFlags center = wxSizerFlags().CenterVertical();
const StyleValidator styleVal(&m_validatorStyle);
wxCheckBox* filterNone = new wxCheckBox(this, Id_None, "wxFILTER_NONE");
filterNone->SetValue(m_noValidation);
fgSizer->Add(filterNone);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "No filtering takes place."));
fgSizer->Add(new wxCheckBox(this, Id_Empty, "wxFILTER_EMPTY"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Empty strings are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_Ascii, "wxFILTER_ASCII"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Non-ASCII characters are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_Alpha, "wxFILTER_ALPHA"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Non-alpha characters are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_Alphanumeric, "wxFILTER_ALPHANUMERIC"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Non-alphanumeric characters are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_Digits, "wxFILTER_DIGITS"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Non-digit characters are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_Numeric, "wxFILTER_NUMERIC"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Non-numeric characters are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_IncludeList, "wxFILTER_INCLUDE_LIST"), center)
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxTextCtrl(this, Id_IncludeListTxt), wxSizerFlags().Expand())
->GetWindow()->Bind(wxEVT_KILL_FOCUS, &TextValidatorDialog::OnKillFocus, this);
fgSizer->Add(new wxCheckBox(this, Id_IncludeCharList, "wxFILTER_INCLUDE_CHAR_LIST"), center)
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxTextCtrl(this, Id_IncludeCharListTxt, wxString(), wxDefaultPosition,
wxDefaultSize, 0, wxGenericValidator(&m_charIncludes)),
wxSizerFlags().Expand())
->GetWindow()->Bind(wxEVT_KILL_FOCUS, &TextValidatorDialog::OnKillFocus, this);
fgSizer->Add(new wxCheckBox(this, Id_ExcludeList, "wxFILTER_EXCLUDE_LIST"), center)
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxTextCtrl(this, Id_ExcludeListTxt), wxSizerFlags().Expand())
->GetWindow()->Bind(wxEVT_KILL_FOCUS, &TextValidatorDialog::OnKillFocus, this);
fgSizer->Add(new wxCheckBox(this, Id_ExcludeCharList, "wxFILTER_EXCLUDE_CHAR_LIST"), center)
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxTextCtrl(this, Id_ExcludeCharListTxt, wxString(), wxDefaultPosition,
wxDefaultSize, 0, wxGenericValidator(&m_charExcludes)),
wxSizerFlags().Expand())
->GetWindow()->Bind(wxEVT_KILL_FOCUS, &TextValidatorDialog::OnKillFocus, this);
fgSizer->Add(new wxCheckBox(this, Id_Xdigits, "wxFILTER_XDIGITS"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Non-xdigit characters are filtered out."));
fgSizer->Add(new wxCheckBox(this, Id_Space, "wxFILTER_SPACE"))
->GetWindow()->SetValidator(styleVal);
fgSizer->Add(new wxStaticText(this, wxID_ANY, "Allow spaces."));
// Set the main sizer.
wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL );
mainsizer->Add(fgSizer, wxSizerFlags(1).Border(wxALL, 10).Expand());
mainsizer->Add(CreateButtonSizer(wxOK | wxCANCEL),
wxSizerFlags().Expand().DoubleBorder());
SetSizer(mainsizer);
mainsizer->SetSizeHints(this);
// Bind event handlers.
Bind(wxEVT_CHECKBOX, &TextValidatorDialog::OnChecked, this);
Bind(wxEVT_UPDATE_UI, &TextValidatorDialog::OnUpdateUI,
this, Id_Ascii, Id_ExcludeCharListTxt);
}
void TextValidatorDialog::OnUpdateUI(wxUpdateUIEvent& event)
{
event.Enable(!m_noValidation);
if ( m_noValidation )
event.Check(false);
}
void TextValidatorDialog::OnChecked(wxCommandEvent& event)
{
if ( event.GetId() == Id_None )
{
m_noValidation = event.IsChecked();
if ( m_noValidation )
{
long style = wxFILTER_NONE;
// we should keep this flag on if it has been set.
if ( HasFlag(wxFILTER_EMPTY) )
style = wxFILTER_EMPTY;
m_validatorStyle = style;
m_charIncludes.clear();
m_charExcludes.clear();
m_includes.clear();
m_excludes.clear();
}
}
}
void TextValidatorDialog::OnKillFocus(wxFocusEvent &event)
{
wxTextCtrl* txtCtrl = wxDynamicCast(event.GetEventObject(), wxTextCtrl);
if ( txtCtrl && txtCtrl->IsModified() )
{
const int id = event.GetId();
if ( id == Id_IncludeCharListTxt )
{
m_charIncludes = txtCtrl->GetValue();
}
else if ( id == Id_ExcludeCharListTxt )
{
m_charExcludes = txtCtrl->GetValue();
}
else if ( id == Id_IncludeListTxt )
{
m_includes = wxSplit(txtCtrl->GetValue(), ' ');
}
else if ( id == Id_ExcludeListTxt )
{
m_excludes = wxSplit(txtCtrl->GetValue(), ' ');
}
}
event.Skip();
}
void TextValidatorDialog::ApplyValidator()
{
if ( !m_txtCtrl )
return;
wxString tooltip = "uses wxTextValidator with ";
if ( m_noValidation )
{
tooltip += "wxFILTER_NONE|";
}
else
{
if ( HasFlag(wxFILTER_ASCII) )
tooltip += "wxFILTER_ASCII|";
if ( HasFlag(wxFILTER_ALPHA) )
tooltip += "wxFILTER_ALPHA|";
if ( HasFlag(wxFILTER_ALPHANUMERIC) )
tooltip += "wxFILTER_ALPHANUMERIC|";
if ( HasFlag(wxFILTER_DIGITS) )
tooltip += "wxFILTER_DIGITS|";
if ( HasFlag(wxFILTER_NUMERIC) )
tooltip += "wxFILTER_NUMERIC|";
if ( HasFlag(wxFILTER_XDIGITS) )
tooltip += "wxFILTER_XDIGITS|";
if ( HasFlag(wxFILTER_SPACE) )
tooltip += "wxFILTER_SPACE|";
if ( HasFlag(wxFILTER_INCLUDE_LIST) )
tooltip += "wxFILTER_INCLUDE_LIST|";
if ( HasFlag(wxFILTER_INCLUDE_CHAR_LIST) )
tooltip += "wxFILTER_INCLUDE_CHAR_LIST|";
if ( HasFlag(wxFILTER_EXCLUDE_LIST) )
tooltip += "wxFILTER_EXCLUDE_LIST|";
if ( HasFlag(wxFILTER_EXCLUDE_CHAR_LIST) )
tooltip += "wxFILTER_EXCLUDE_CHAR_LIST|";
}
if ( HasFlag(wxFILTER_EMPTY) )
{
tooltip += "wxFILTER_EMPTY|";
}
tooltip.RemoveLast(); // remove the trailing '|' char.
if ( !m_charIncludes.empty() )
{
tooltip += "\nAllowed chars: ";
tooltip += m_charIncludes;
}
if ( !m_charExcludes.empty() )
{
tooltip += "\nDisallowed chars: ";
tooltip += m_charExcludes;
}
m_txtCtrl->SetToolTip(tooltip);
// Prepare and set the wxTextValidator
wxTextValidator txtVal(m_validatorStyle, &g_data.m_string);
txtVal.SetCharIncludes(m_charIncludes);
txtVal.SetCharExcludes(m_charExcludes);
txtVal.SetIncludes(m_includes);
txtVal.SetExcludes(m_excludes);
m_txtCtrl->SetValidator(txtVal);
m_txtCtrl->SetFocus();
}
bool TextValidatorDialog::StyleValidator::TransferToWindow()
{
wxASSERT( wxDynamicCast(m_validatorWindow, wxCheckBox) );
if ( m_style )
{
wxCheckBox* cb = (wxCheckBox*)GetWindow();
if ( !cb )
return false;
const long style = 1 << (cb->GetId()-wxID_HIGHEST-1);
cb->SetValue((*m_style & style) != 0);
}
return true;
}
bool TextValidatorDialog::StyleValidator::TransferFromWindow()
{
wxASSERT( wxDynamicCast(m_validatorWindow, wxCheckBox) );
if ( m_style )
{
wxCheckBox* cb = (wxCheckBox*)GetWindow();
if ( !cb )
return false;
const long style = 1 << (cb->GetId()-wxID_HIGHEST-1);
if ( cb->IsChecked() )
*m_style |= style;
else
*m_style &= ~style;
}
return true;
}

View File

@@ -48,7 +48,8 @@ public:
const wxSize& size = wxDefaultSize, const wxSize& size = wxDefaultSize,
const long style = wxDEFAULT_DIALOG_STYLE); const long style = wxDEFAULT_DIALOG_STYLE);
bool TransferDataToWindow() wxOVERRIDE; void OnChangeValidator(wxCommandEvent& event);
wxTextCtrl *m_text; wxTextCtrl *m_text;
wxComboBox *m_combobox; wxComboBox *m_combobox;
@@ -56,6 +57,81 @@ public:
wxTextCtrl *m_numericTextDouble; wxTextCtrl *m_numericTextDouble;
}; };
// ----------------------------------------------------------------------------
// TextValidatorDialog
// ----------------------------------------------------------------------------
class TextValidatorDialog : public wxDialog
{
public:
TextValidatorDialog(wxWindow *parent, wxTextCtrl* txtCtrl);
void OnUpdateUI(wxUpdateUIEvent& event);
void OnChecked(wxCommandEvent& event);
void OnKillFocus( wxFocusEvent &event );
void ApplyValidator();
private:
// Special validator for our checkboxes
class StyleValidator : public wxValidator
{
public:
StyleValidator(long* style) { m_style = style; }
virtual bool Validate(wxWindow *WXUNUSED(parent)) wxOVERRIDE { return true; }
virtual wxObject* Clone() const wxOVERRIDE { return new StyleValidator(*this); }
// Called to transfer data to the window
virtual bool TransferToWindow() wxOVERRIDE;
// Called to transfer data from the window
virtual bool TransferFromWindow() wxOVERRIDE;
private:
long* m_style;
};
private:
bool HasFlag(wxTextValidatorStyle style) const
{
return (m_validatorStyle & style) != 0;
}
enum
{
// CheckBoxes Ids (should be in sync with wxTextValidatorStyle)
Id_None = wxID_HIGHEST,
Id_Empty,
Id_Ascii,
Id_Alpha,
Id_Alphanumeric,
Id_Digits,
Id_Numeric,
Id_IncludeList,
Id_IncludeCharList,
Id_ExcludeList,
Id_ExcludeCharList,
Id_Xdigits,
Id_Space,
// TextCtrls Ids
Id_IncludeListTxt,
Id_IncludeCharListTxt,
Id_ExcludeListTxt,
Id_ExcludeCharListTxt,
};
wxTextCtrl* const m_txtCtrl;
bool m_noValidation;
long m_validatorStyle;
wxString m_charIncludes;
wxString m_charExcludes;
wxArrayString m_includes;
wxArrayString m_excludes;
};
class MyData class MyData
{ {
public: public:

View File

@@ -23,6 +23,7 @@
#include <stdio.h> #include <stdio.h>
#include "wx/textctrl.h" #include "wx/textctrl.h"
#include "wx/combobox.h" #include "wx/combobox.h"
#include "wx/log.h"
#include "wx/utils.h" #include "wx/utils.h"
#include "wx/msgdlg.h" #include "wx/msgdlg.h"
#include "wx/intl.h" #include "wx/intl.h"
@@ -76,25 +77,6 @@ wxTextValidator::wxTextValidator(const wxTextValidator& val)
void wxTextValidator::SetStyle(long style) void wxTextValidator::SetStyle(long style)
{ {
m_validatorStyle = 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) bool wxTextValidator::Copy(const wxTextValidator& val)
@@ -104,6 +86,8 @@ bool wxTextValidator::Copy(const wxTextValidator& val)
m_validatorStyle = val.m_validatorStyle; m_validatorStyle = val.m_validatorStyle;
m_stringValue = val.m_stringValue; m_stringValue = val.m_stringValue;
m_charIncludes = val.m_charIncludes;
m_charExcludes = val.m_charExcludes;
m_includes = val.m_includes; m_includes = val.m_includes;
m_excludes = val.m_excludes; m_excludes = val.m_excludes;
@@ -153,25 +137,7 @@ bool wxTextValidator::Validate(wxWindow *parent)
if ( !text ) if ( !text )
return false; return false;
wxString val(text->GetValue()); const wxString& errormsg = IsValid(text->GetValue());
wxString errormsg;
// We can only do some kinds of validation once the input is complete, so
// check for them here:
if ( HasFlag(wxFILTER_EMPTY) && val.empty() )
errormsg = _("Required information entry is empty.");
else if ( HasFlag(wxFILTER_INCLUDE_LIST) && m_includes.Index(val) == wxNOT_FOUND )
errormsg = wxString::Format(_("'%s' is not one of the valid strings"), val);
else if ( HasFlag(wxFILTER_EXCLUDE_LIST) && m_excludes.Index(val) != wxNOT_FOUND )
errormsg = wxString::Format(_("'%s' is one of the invalid strings"), val);
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() ) if ( !errormsg.empty() )
{ {
@@ -215,89 +181,98 @@ bool wxTextValidator::TransferFromWindow()
return true; return true;
} }
// IRIX mipsPro refuses to compile wxStringCheck<func>() if func is inline so wxString wxTextValidator::IsValid(const wxString& str) const
// 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 ( HasFlag(wxFILTER_EMPTY) && str.empty() )
return _("Required information entry is empty.");
else if ( IsExcluded(str) )
return wxString::Format(_("'%s' is one of the invalid strings"), str);
else if ( !IsIncluded(str) )
return wxString::Format(_("'%s' is not one of the valid strings"), str);
bool CheckString(bool (*func)(const wxUniChar&), const wxString& str) // check the whole string for invalid chars.
for ( wxString::const_iterator i = str.begin(), end = str.end();
i != end; ++i )
{ {
for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i ) if ( !IsValidChar(*i) )
{ {
if ( !func(*i) ) return wxString::Format(
return false; _("'%s' contains invalid character(s)"), str);
}
} }
return true; return wxString();
} }
} // anonymous namespace
wxString wxTextValidator::IsValid(const wxString& val) const
{
// 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_CHAR_LIST) && !ContainsOnlyIncludedCharacters(val) )
return _("'%s' doesn't consist only of valid characters");
if ( HasFlag(wxFILTER_EXCLUDE_CHAR_LIST) && ContainsExcludedCharacters(val) )
return _("'%s' contains illegal characters");
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) void wxTextValidator::SetCharIncludes(const wxString& chars)
{ {
wxArrayString arr; m_charIncludes.clear();
for ( wxString::const_iterator i = chars.begin(); i != chars.end(); ++i ) AddCharIncludes(chars);
arr.Add(*i); }
SetIncludes(arr); void wxTextValidator::AddCharIncludes(const wxString& chars)
{
m_charIncludes += chars;
} }
void wxTextValidator::SetCharExcludes(const wxString& chars) void wxTextValidator::SetCharExcludes(const wxString& chars)
{ {
wxArrayString arr; m_charExcludes.clear();
for ( wxString::const_iterator i = chars.begin(); i != chars.end(); ++i ) AddCharExcludes(chars);
arr.Add(*i); }
SetExcludes(arr); void wxTextValidator::AddCharExcludes(const wxString& chars)
{
m_charExcludes += chars;
}
void wxTextValidator::SetIncludes(const wxArrayString& includes)
{
// preserve compatibily with versions prior 3.1.3 which used m_includes
// to store the list of char includes.
if ( HasFlag(wxFILTER_INCLUDE_CHAR_LIST) )
{
for ( wxArrayString::const_iterator i = includes.begin(),
end = includes.end(); i != end; ++i )
{
AddCharIncludes(*i);
}
return;
}
m_includes = includes;
}
void wxTextValidator::AddInclude(const wxString& include)
{
m_includes.push_back(include);
}
void wxTextValidator::SetExcludes(const wxArrayString& excludes)
{
// preserve compatibily with versions prior 3.1.3 which used m_excludes
// to store the list of char excludes.
if ( HasFlag(wxFILTER_EXCLUDE_CHAR_LIST) )
{
for ( wxArrayString::const_iterator i = excludes.begin(),
end = excludes.end(); i != end; ++i )
{
AddCharExcludes(*i);
}
return;
}
m_excludes = excludes;
}
void wxTextValidator::AddExclude(const wxString& exclude)
{
m_excludes.push_back(exclude);
} }
void wxTextValidator::OnChar(wxKeyEvent& event) void wxTextValidator::OnChar(wxKeyEvent& event)
@@ -321,8 +296,8 @@ void wxTextValidator::OnChar(wxKeyEvent& event)
if (keyCode < WXK_SPACE || keyCode == WXK_DELETE) if (keyCode < WXK_SPACE || keyCode == WXK_DELETE)
return; return;
wxString str((wxUniChar)keyCode, 1); // Filter out invalid characters
if (IsValid(str).empty()) if ( IsValidChar(static_cast<wxUniChar>(keyCode)) )
return; return;
if ( !wxValidator::IsSilent() ) if ( !wxValidator::IsSilent() )
@@ -332,6 +307,71 @@ void wxTextValidator::OnChar(wxKeyEvent& event)
event.Skip(false); event.Skip(false);
} }
bool wxTextValidator::IsValidChar(const wxUniChar& c) const
{
if ( !m_validatorStyle ) // no filtering if HasFlag(wxFILTER_NONE)
return true;
if ( IsCharExcluded(c) ) // disallow any char in the m_charExcludes.
return false;
if ( IsCharIncluded(c) ) // allow any char in the m_charIncludes.
return true;
if ( !HasFlag(wxFILTER_CC) )
{
// Validity is entirely determined by the exclude/include char lists
// and this character is in neither, so consider that it is valid if
// and only if we accept anything.
return !HasFlag(wxFILTER_INCLUDE_CHAR_LIST);
}
if ( HasFlag(wxFILTER_SPACE) && wxIsspace(c) )
return true;
if ( HasFlag(wxFILTER_ASCII) && c.IsAscii() )
return true;
if ( HasFlag(wxFILTER_NUMERIC) && wxIsNumeric(c) )
return true;
if ( HasFlag(wxFILTER_ALPHANUMERIC) && wxIsalnum(c) )
return true;
if ( HasFlag(wxFILTER_ALPHA) && wxIsalpha(c) )
return true;
if ( HasFlag(wxFILTER_DIGITS) && wxIsdigit(c) )
return true;
if ( HasFlag(wxFILTER_XDIGITS) && wxIsxdigit(c) )
return true;
// If we are here, this means that the char c does not belong to any of the
// character classes checked above (e.g. emoji chars) so just return false.
return false;
}
// kept for compatibility reasons.
bool wxTextValidator::ContainsOnlyIncludedCharacters(const wxString& str) const
{
for ( wxString::const_iterator i = str.begin(), end = str.end();
i != end; ++i )
{
if ( !IsCharIncluded(*i) )
return false;
}
return true;
}
// kept for compatibility reasons.
bool wxTextValidator::ContainsExcludedCharacters(const wxString& str) const
{
for ( wxString::const_iterator i = str.begin(), end = str.end();
i != end; ++i )
{
if ( IsCharExcluded(*i) )
return true;
}
return false;
}
#endif #endif
// wxUSE_VALIDATORS && (wxUSE_TEXTCTRL || wxUSE_COMBOBOX) // wxUSE_VALIDATORS && (wxUSE_TEXTCTRL || wxUSE_COMBOBOX)

View File

@@ -262,9 +262,7 @@ private:
if ( m_combo ) if ( m_combo )
{ {
wxArrayString allowedChars; wxString allowedChars = wxS("0123456789");
for ( wxChar c = wxT('0'); c <= wxT('9'); c++ )
allowedChars.Add(wxString(c, 1));
const wxChar *p2 = m_format.c_str(); const wxChar *p2 = m_format.c_str();
while ( *p2 ) while ( *p2 )
@@ -272,12 +270,12 @@ private:
if ( *p2 == '%') if ( *p2 == '%')
p2 += 2; p2 += 2;
else else
allowedChars.Add(wxString(*p2++, 1)); allowedChars << (*p2++); // append char
} }
#if wxUSE_VALIDATORS #if wxUSE_VALIDATORS
wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST); wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
tv.SetIncludes(allowedChars); tv.SetCharIncludes(allowedChars);
m_combo->SetValidator(tv); m_combo->SetValidator(tv);
#endif #endif

View File

@@ -160,47 +160,41 @@ wxNumericPropertyValidator::
wxNumericPropertyValidator( NumericType numericType, int base ) wxNumericPropertyValidator( NumericType numericType, int base )
: wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST) : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST)
{ {
wxArrayString arr; long style = GetStyle();
arr.Add(wxS("0"));
arr.Add(wxS("1"));
arr.Add(wxS("2"));
arr.Add(wxS("3"));
arr.Add(wxS("4"));
arr.Add(wxS("5"));
arr.Add(wxS("6"));
arr.Add(wxS("7"));
if ( base >= 10 ) // always allow plus and minus signs
wxString allowedChars("+-");
switch ( base )
{ {
arr.Add(wxS("8")); case 2:
arr.Add(wxS("9")); allowedChars += wxS("01");
if ( base >= 16 ) break;
{ case 8:
arr.Add(wxS("a")); arr.Add(wxS("A")); allowedChars += wxS("01234567");
arr.Add(wxS("b")); arr.Add(wxS("B")); break;
arr.Add(wxS("c")); arr.Add(wxS("C")); case 10:
arr.Add(wxS("d")); arr.Add(wxS("D")); style |= wxFILTER_DIGITS;
arr.Add(wxS("e")); arr.Add(wxS("E")); break;
arr.Add(wxS("f")); arr.Add(wxS("F")); case 16:
} style |= wxFILTER_XDIGITS;
break;
default:
wxLogWarning( _("Unknown base %d. Base 10 will be used."), base );
style |= wxFILTER_DIGITS;
} }
if ( numericType == Signed ) if ( numericType == Float )
{ {
arr.Add(wxS("+")); allowedChars += wxS("eE");
arr.Add(wxS("-"));
}
else if ( numericType == Float )
{
arr.Add(wxS("+"));
arr.Add(wxS("-"));
arr.Add(wxS("e")); arr.Add(wxS("E"));
// Use locale-specific decimal point // Use locale-specific decimal point
arr.Add(wxString::Format(wxS("%g"), 1.1)[1]); allowedChars += wxString::Format(wxS("%g"), 1.1)[1];
} }
SetIncludes(arr); SetStyle(style);
SetCharIncludes(allowedChars);
} }
bool wxNumericPropertyValidator::Validate(wxWindow* parent) bool wxNumericPropertyValidator::Validate(wxWindow* parent)
@@ -2021,15 +2015,7 @@ wxValidator* wxFileProperty::GetClassValidator()
static wxString v; static wxString v;
wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v); wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v);
wxArrayString exChars; validator->SetCharExcludes(wxString("?*|<>\""));
exChars.Add(wxS("?"));
exChars.Add(wxS("*"));
exChars.Add(wxS("|"));
exChars.Add(wxS("<"));
exChars.Add(wxS(">"));
exChars.Add(wxS("\""));
validator->SetExcludes(exChars);
WX_PG_DOGETVALIDATOR_EXIT(validator) WX_PG_DOGETVALIDATOR_EXIT(validator)
#else #else

View File

@@ -260,6 +260,7 @@ TEST_GUI_OBJECTS = \
test_gui_wrapsizer.o \ test_gui_wrapsizer.o \
test_gui_toplevel.o \ test_gui_toplevel.o \
test_gui_valnum.o \ test_gui_valnum.o \
test_gui_valtext.o \
test_gui_clientsize.o \ test_gui_clientsize.o \
test_gui_setsize.o \ test_gui_setsize.o \
test_gui_xrctest.o test_gui_xrctest.o
@@ -1052,6 +1053,9 @@ test_gui_toplevel.o: $(srcdir)/toplevel/toplevel.cpp $(TEST_GUI_ODEP)
test_gui_valnum.o: $(srcdir)/validators/valnum.cpp $(TEST_GUI_ODEP) test_gui_valnum.o: $(srcdir)/validators/valnum.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/validators/valnum.cpp $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/validators/valnum.cpp
test_gui_valtext.o: $(srcdir)/validators/valtext.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/validators/valtext.cpp
test_gui_clientsize.o: $(srcdir)/window/clientsize.cpp $(TEST_GUI_ODEP) test_gui_clientsize.o: $(srcdir)/window/clientsize.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/window/clientsize.cpp $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/window/clientsize.cpp

View File

@@ -247,6 +247,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_wrapsizer.obj \ $(OBJS)\test_gui_wrapsizer.obj \
$(OBJS)\test_gui_toplevel.obj \ $(OBJS)\test_gui_toplevel.obj \
$(OBJS)\test_gui_valnum.obj \ $(OBJS)\test_gui_valnum.obj \
$(OBJS)\test_gui_valtext.obj \
$(OBJS)\test_gui_clientsize.obj \ $(OBJS)\test_gui_clientsize.obj \
$(OBJS)\test_gui_setsize.obj \ $(OBJS)\test_gui_setsize.obj \
$(OBJS)\test_gui_xrctest.obj $(OBJS)\test_gui_xrctest.obj
@@ -1107,6 +1108,9 @@ $(OBJS)\test_gui_toplevel.obj: .\toplevel\toplevel.cpp
$(OBJS)\test_gui_valnum.obj: .\validators\valnum.cpp $(OBJS)\test_gui_valnum.obj: .\validators\valnum.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\validators\valnum.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\validators\valnum.cpp
$(OBJS)\test_gui_valtext.obj: .\validators\valtext.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\validators\valtext.cpp
$(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp $(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\window\clientsize.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\window\clientsize.cpp

View File

@@ -242,6 +242,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_wrapsizer.o \ $(OBJS)\test_gui_wrapsizer.o \
$(OBJS)\test_gui_toplevel.o \ $(OBJS)\test_gui_toplevel.o \
$(OBJS)\test_gui_valnum.o \ $(OBJS)\test_gui_valnum.o \
$(OBJS)\test_gui_valtext.o \
$(OBJS)\test_gui_clientsize.o \ $(OBJS)\test_gui_clientsize.o \
$(OBJS)\test_gui_setsize.o \ $(OBJS)\test_gui_setsize.o \
$(OBJS)\test_gui_xrctest.o $(OBJS)\test_gui_xrctest.o
@@ -1084,6 +1085,9 @@ $(OBJS)\test_gui_toplevel.o: ./toplevel/toplevel.cpp
$(OBJS)\test_gui_valnum.o: ./validators/valnum.cpp $(OBJS)\test_gui_valnum.o: ./validators/valnum.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\test_gui_valtext.o: ./validators/valtext.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\test_gui_clientsize.o: ./window/clientsize.cpp $(OBJS)\test_gui_clientsize.o: ./window/clientsize.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<

View File

@@ -253,6 +253,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_wrapsizer.obj \ $(OBJS)\test_gui_wrapsizer.obj \
$(OBJS)\test_gui_toplevel.obj \ $(OBJS)\test_gui_toplevel.obj \
$(OBJS)\test_gui_valnum.obj \ $(OBJS)\test_gui_valnum.obj \
$(OBJS)\test_gui_valtext.obj \
$(OBJS)\test_gui_clientsize.obj \ $(OBJS)\test_gui_clientsize.obj \
$(OBJS)\test_gui_setsize.obj \ $(OBJS)\test_gui_setsize.obj \
$(OBJS)\test_gui_xrctest.obj $(OBJS)\test_gui_xrctest.obj
@@ -1298,6 +1299,9 @@ $(OBJS)\test_gui_toplevel.obj: .\toplevel\toplevel.cpp
$(OBJS)\test_gui_valnum.obj: .\validators\valnum.cpp $(OBJS)\test_gui_valnum.obj: .\validators\valnum.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\validators\valnum.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\validators\valnum.cpp
$(OBJS)\test_gui_valtext.obj: .\validators\valtext.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\validators\valtext.cpp
$(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp $(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\window\clientsize.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\window\clientsize.cpp

View File

@@ -272,6 +272,7 @@
sizers/wrapsizer.cpp sizers/wrapsizer.cpp
toplevel/toplevel.cpp toplevel/toplevel.cpp
validators/valnum.cpp validators/valnum.cpp
validators/valtext.cpp
window/clientsize.cpp window/clientsize.cpp
window/setsize.cpp window/setsize.cpp
xml/xrctest.cpp xml/xrctest.cpp

View File

@@ -595,6 +595,9 @@
<File <File
RelativePath=".\validators\valnum.cpp"> RelativePath=".\validators\valnum.cpp">
</File> </File>
<File
RelativePath=".\validators\valtext.cpp">
</File>
<File <File
RelativePath=".\controls\virtlistctrltest.cpp"> RelativePath=".\controls\virtlistctrltest.cpp">
</File> </File>

View File

@@ -1262,6 +1262,10 @@
RelativePath=".\validators\valnum.cpp" RelativePath=".\validators\valnum.cpp"
> >
</File> </File>
<File
RelativePath=".\validators\valtext.cpp"
>
</File>
<File <File
RelativePath=".\controls\virtlistctrltest.cpp" RelativePath=".\controls\virtlistctrltest.cpp"
> >

View File

@@ -1234,6 +1234,10 @@
RelativePath=".\validators\valnum.cpp" RelativePath=".\validators\valnum.cpp"
> >
</File> </File>
<File
RelativePath=".\validators\valtext.cpp"
>
</File>
<File <File
RelativePath=".\controls\virtlistctrltest.cpp" RelativePath=".\controls\virtlistctrltest.cpp"
> >

View File

@@ -0,0 +1,190 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/validators/valtext.cpp
// Purpose: wxTextValidator unit test
// Author: Ali Kettab
// Created: 2019-01-01
///////////////////////////////////////////////////////////////////////////////
#include "testprec.h"
#if wxUSE_VALIDATORS && wxUSE_UIACTIONSIMULATOR
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/textctrl.h"
#include "wx/valtext.h"
#endif // WX_PRECOMP
#include "wx/uiaction.h"
class TextValidatorTestCase
{
public:
TextValidatorTestCase()
: m_text(new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY))
{
}
~TextValidatorTestCase()
{
delete m_text;
}
protected:
wxTextCtrl* const m_text;
};
#define TEXT_VALIDATOR_TEST_CASE(name, tags) \
TEST_CASE_METHOD(TextValidatorTestCase, name, tags)
TEXT_VALIDATOR_TEST_CASE("wxTextValidator::IsValid", "[wxTextValidator][filters]")
{
wxString value = "";
wxTextValidator val(wxFILTER_NONE, &value);
SECTION("wxFILTER_NONE - no filtering should take place")
{
CHECK( val.IsValid("wx-90.?! @_~E+{").empty() );
}
SECTION("wxFILTER_EMPTY - empty strings are filtered out")
{
val.SetStyle(wxFILTER_EMPTY);
CHECK( !val.IsValid("").empty() );
CHECK( val.IsValid(" ").empty() ); // space is valid
}
SECTION("wxFILTER_ASCII - non-ASCII characters are filtered out")
{
val.SetStyle(wxFILTER_ASCII);
CHECK( val.IsValid("wx-90.?! @_~E+{").empty() );
}
SECTION("wxFILTER_ALPHA - non-alpha characters are filtered out")
{
val.SetStyle(wxFILTER_ALPHA);
CHECK( val.IsValid("wx").empty() );
CHECK( !val.IsValid("wx_").empty() ); // _ is not alpha
}
SECTION("wxFILTER_ALPHANUMERIC - non-alphanumeric characters are filtered out")
{
val.SetStyle(wxFILTER_ALPHANUMERIC);
CHECK( val.IsValid("wx01").empty() );
CHECK( !val.IsValid("wx 01").empty() ); // 'space' is not alphanumeric
}
SECTION("wxFILTER_DIGITS - non-digit characters are filtered out")
{
val.SetStyle(wxFILTER_DIGITS);
CHECK( val.IsValid("97").empty() );
CHECK( !val.IsValid("9.7").empty() ); // . is not digit
}
SECTION("wxFILTER_XDIGITS - non-xdigit characters are filtered out")
{
val.SetStyle(wxFILTER_XDIGITS);
CHECK( val.IsValid("90AEF").empty() );
CHECK( !val.IsValid("90GEF").empty() ); // G is not xdigit
}
SECTION("wxFILTER_NUMERIC - non-numeric characters are filtered out")
{
val.SetStyle(wxFILTER_NUMERIC);
CHECK( val.IsValid("+90.e-2").empty() );
CHECK( !val.IsValid("-8.5#0").empty() ); // # is not numeric
}
SECTION("wxFILTER_INCLUDE_LIST - use include list")
{
val.SetStyle(wxFILTER_INCLUDE_LIST);
wxArrayString includes;
includes.push_back("wxMSW");
includes.push_back("wxGTK");
includes.push_back("wxOSX");
val.SetIncludes(includes);
CHECK( val.IsValid("wxGTK").empty() );
CHECK( !val.IsValid("wxQT").empty() ); // wxQT is not included
SECTION("wxFILTER_EXCLUDE_LIST - use exclude with include list")
{
wxArrayString excludes;
excludes.push_back("wxGTK");
excludes.push_back("wxGTK1");
val.SetExcludes(excludes);
CHECK( val.IsValid("wxOSX").empty() );
CHECK( !val.IsValid("wxGTK").empty() ); // wxGTK now excluded
}
}
SECTION("wxFILTER_EXCLUDE_LIST - use exclude list")
{
val.SetStyle(wxFILTER_EXCLUDE_LIST);
wxArrayString excludes;
excludes.push_back("wxMSW");
excludes.push_back("wxGTK");
excludes.push_back("wxOSX");
val.SetExcludes(excludes);
CHECK( val.IsValid("wxQT & wxUNIV").empty() );
CHECK( !val.IsValid("wxMSW").empty() ); // wxMSW is excluded
SECTION("wxFILTER_INCLUDE_LIST - use include with exclude list")
{
wxArrayString includes;
includes.push_back("wxGTK");
val.SetIncludes(includes); // exclusion takes priority over inclusion.
CHECK( val.IsValid("wxUNIV").empty() );
CHECK( !val.IsValid("wxMSW").empty() ); // wxMSW still excluded
}
}
SECTION("wxFILTER_INCLUDE_CHAR_LIST - use include char list")
{
val.SetStyle(wxFILTER_INCLUDE_CHAR_LIST);
val.SetCharIncludes("tuvwxyz.012+-");
CHECK( val.IsValid("0.2t+z-1").empty() );
CHECK( !val.IsValid("x*y").empty() ); // * is not included
val.AddCharIncludes("*");
CHECK( val.IsValid("x*y").empty() ); // * now included
CHECK( !val.IsValid("x%y").empty() ); // % is not included
val.AddCharExcludes("*"); // exclusion takes priority over inclusion.
CHECK( !val.IsValid("x*y").empty() ); // * now excluded
}
SECTION("wxFILTER_EXCLUDE_CHAR_LIST - use exclude char list")
{
val.SetStyle(wxFILTER_EXCLUDE_CHAR_LIST);
val.SetCharExcludes("tuvwxyz.012+-");
CHECK( val.IsValid("A*B=?").empty() );
CHECK( !val.IsValid("0.6/t").empty() ); // t is excluded
val.AddCharIncludes("t"); // exclusion takes priority over inclusion.
CHECK( !val.IsValid("0.6/t").empty() ); // t still excluded
}
}
#endif // wxUSE_VALIDATORS && wxUSE_UIACTIONSIMULATOR