--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: src/common/valnumtext.cpp
+// Purpose: Numeric validator classes implementation
+// Author: Vadim Zeitlin based on the submission of Fulvio Senore
+// Created: 2010-11-06
+// Copyright: (c) 2010 wxWidgets team
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// Declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#if wxUSE_VALIDATORS && wxUSE_TEXTCTRL
+
+#ifndef WX_PRECOMP
+ #include "wx/textctrl.h"
+ #include "wx/combobox.h"
+#endif
+
+#include "wx/valnum.h"
+#include "wx/numformatter.h"
+
+// ============================================================================
+// wxNumValidatorBase implementation
+// ============================================================================
+
+BEGIN_EVENT_TABLE(wxNumValidatorBase, wxValidator)
+ EVT_CHAR(wxNumValidatorBase::OnChar)
+ EVT_KILL_FOCUS(wxNumValidatorBase::OnKillFocus)
+END_EVENT_TABLE()
+
+int wxNumValidatorBase::GetFormatFlags() const
+{
+ int flags = wxNumberFormatter::Style_None;
+ if ( m_style & wxNUM_VAL_THOUSANDS_SEPARATOR )
+ flags |= wxNumberFormatter::Style_WithThousandsSep;
+ if ( m_style & wxNUM_VAL_NO_TRAILING_ZEROES )
+ flags |= wxNumberFormatter::Style_NoTrailingZeroes;
+
+ return flags;
+}
+
+wxTextEntry *wxNumValidatorBase::GetTextEntry() const
+{
+#if wxUSE_TEXTCTRL
+ if ( wxTextCtrl *text = wxDynamicCast(m_validatorWindow, wxTextCtrl) )
+ return text;
+#endif // wxUSE_TEXTCTRL
+
+#if wxUSE_COMBOBOX
+ if ( wxComboBox *combo = wxDynamicCast(m_validatorWindow, wxComboBox) )
+ return combo;
+#endif // wxUSE_COMBOBOX
+
+ wxFAIL_MSG("Can only be used with wxTextCtrl or wxComboBox");
+
+ return NULL;
+}
+
+void
+wxNumValidatorBase::GetCurrentValueAndInsertionPoint(wxString& val,
+ int& pos) const
+{
+ wxTextEntry * const control = GetTextEntry();
+ if ( !control )
+ return;
+
+ val = control->GetValue();
+ pos = control->GetInsertionPoint();
+
+ long selFrom, selTo;
+ control->GetSelection(&selFrom, &selTo);
+
+ const long selLen = selTo - selFrom;
+ if ( selLen )
+ {
+ // Remove selected text because pressing a key would make it disappear.
+ val.erase(selFrom, selLen);
+
+ // And adjust the insertion point to have correct position in the new
+ // string.
+ if ( pos > selFrom )
+ {
+ if ( pos >= selTo )
+ pos -= selLen;
+ else
+ pos = selFrom;
+ }
+ }
+}
+
+bool wxNumValidatorBase::IsMinusOk(const wxString& val, int pos) const
+{
+ // Minus is only ever accepted in the beginning of the string.
+ if ( pos != 0 )
+ return false;
+
+ // And then only if there is no existing minus sign there.
+ if ( !val.empty() && val[0] == '-' )
+ return false;
+
+ return true;
+}
+
+void wxNumValidatorBase::OnChar(wxKeyEvent& event)
+{
+ // By default we just validate this key so don't prevent the normal
+ // handling from taking place.
+ event.Skip();
+
+ if ( !m_validatorWindow )
+ return;
+
+#if wxUSE_UNICODE
+ const int ch = event.GetUnicodeKey();
+ if ( ch == WXK_NONE )
+ {
+ // It's a character without any Unicode equivalent at all, e.g. cursor
+ // arrow or function key, we never filter those.
+ return;
+ }
+#else // !wxUSE_UNICODE
+ const int ch = event.GetKeyCode();
+ if ( ch > WXK_DELETE )
+ {
+ // Not a character neither.
+ return;
+ }
+#endif // wxUSE_UNICODE/!wxUSE_UNICODE
+
+ if ( ch < WXK_SPACE || ch == WXK_DELETE )
+ {
+ // Allow ASCII control characters and Delete.
+ return;
+ }
+
+ // Check if this character is allowed in the current state.
+ wxString val;
+ int pos;
+ GetCurrentValueAndInsertionPoint(val, pos);
+
+ if ( !IsCharOk(val, pos, ch) )
+ {
+ if ( !wxValidator::IsSilent() )
+ wxBell();
+
+ // Do not skip the event in this case, stop handling it here.
+ event.Skip(false);
+ }
+}
+
+void wxNumValidatorBase::OnKillFocus(wxFocusEvent& event)
+{
+ wxTextEntry * const control = GetTextEntry();
+ if ( !control )
+ return;
+
+ // When we change the control value below, its "modified" status is reset
+ // so we need to explicitly keep it marked as modified if it was so in the
+ // first place.
+ //
+ // Notice that only wxTextCtrl (and not wxTextEntry) has
+ // IsModified()/MarkDirty() methods hence the need for dynamic cast.
+ wxTextCtrl * const text = wxDynamicCast(m_validatorWindow, wxTextCtrl);
+ const bool wasModified = text ? text->IsModified() : false;
+
+ control->ChangeValue(NormalizeString(control->GetValue()));
+
+ if ( wasModified )
+ text->MarkDirty();
+
+ event.Skip();
+}
+
+// ============================================================================
+// wxIntegerValidatorBase implementation
+// ============================================================================
+
+wxString wxIntegerValidatorBase::ToString(LongestValueType value) const
+{
+ return wxNumberFormatter::ToString(value, GetFormatFlags());
+}
+
+bool
+wxIntegerValidatorBase::FromString(const wxString& s, LongestValueType *value)
+{
+ return wxNumberFormatter::FromString(s, value);
+}
+
+bool
+wxIntegerValidatorBase::IsCharOk(const wxString& val, int pos, wxChar ch) const
+{
+ // We may accept minus sign if we can represent negative numbers at all.
+ if ( ch == '-' )
+ {
+ // Notice that entering '-' can make our value invalid, for example if
+ // we're limited to -5..15 range and the current value is 12, then the
+ // new value would be (invalid) -12. We consider it better to let the
+ // user do this because perhaps he is going to press Delete key next to
+ // make it -2 and forcing him to delete 1 first would be unnatural.
+ //
+ // TODO: It would be nice to indicate that the current control contents
+ // is invalid (if it's indeed going to be the case) once
+ // wxValidator supports doing this non-intrusively.
+ return m_min < 0 && IsMinusOk(val, pos);
+ }
+
+ // We only accept digits here (remember that '-' is taken care of by the
+ // base class already).
+ if ( ch < '0' || ch > '9' )
+ return false;
+
+ // And the value after insertion needs to be in the defined range.
+ LongestValueType value;
+ if ( !FromString(GetValueAfterInsertingChar(val, pos, ch), &value) )
+ return false;
+
+ return IsInRange(value);
+}
+
+// ============================================================================
+// wxFloatingPointValidatorBase implementation
+// ============================================================================
+
+wxString wxFloatingPointValidatorBase::ToString(LongestValueType value) const
+{
+ return wxNumberFormatter::ToString(value, m_precision, GetFormatFlags());
+}
+
+bool
+wxFloatingPointValidatorBase::FromString(const wxString& s,
+ LongestValueType *value)
+{
+ return wxNumberFormatter::FromString(s, value);
+}
+
+bool
+wxFloatingPointValidatorBase::IsCharOk(const wxString& val,
+ int pos,
+ wxChar ch) const
+{
+ // We may accept minus sign if we can represent negative numbers at all.
+ if ( ch == '-' )
+ return m_min < 0 && IsMinusOk(val, pos);
+
+ const wxChar separator = wxNumberFormatter::GetDecimalSeparator();
+ if ( ch == separator )
+ {
+ if ( val.find(separator) != wxString::npos )
+ {
+ // There is already a decimal separator, can't insert another one.
+ return false;
+ }
+
+ // Prepending a separator before the minus sign isn't allowed.
+ if ( pos == 0 && !val.empty() && val[0] == '-' )
+ return false;
+
+ // Otherwise always accept it, adding a decimal separator doesn't
+ // change the number value and, in particular, can't make it invalid.
+ // OTOH the checks below might not pass because strings like "." or
+ // "-." are not valid numbers so parsing them would fail, hence we need
+ // to treat it specially here.
+ return true;
+ }
+
+ // Must be a digit then.
+ if ( ch < '0' || ch > '9' )
+ return false;
+
+ // Check whether the value we'd obtain if we accepted this key is correct.
+ const wxString newval(GetValueAfterInsertingChar(val, pos, ch));
+
+ LongestValueType value;
+ if ( !FromString(newval, &value) )
+ return false;
+
+ // Also check that it doesn't have too many decimal digits.
+ const size_t posSep = newval.find(separator);
+ if ( posSep != wxString::npos && newval.length() - posSep - 1 > m_precision )
+ return false;
+
+ // Finally check whether it is in the range.
+ return IsInRange(value);
+}
+
+#endif // wxUSE_VALIDATORS && wxUSE_TEXTCTRL