Files
wxWidgets/src/common/valnum.cpp
Dimitri Schoolwerth 80fdcdb90e No changes, synchronised source names that appear commented at the top of files with the actual path to the files.
Fixed commented names (path, filename, and extension) of files in include/ and src/. Prepended the names in src/ with "src/" everywhere, while starting those in include/wx/ with "wx/".

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67254 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2011-03-20 00:14:35 +00:00

300 lines
9.1 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/valnum.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