1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/valnum.cpp
3 // Purpose: Numeric validator classes implementation
4 // Author: Vadim Zeitlin based on the submission of Fulvio Senore
6 // Copyright: (c) 2010 wxWidgets team
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
25 #if wxUSE_VALIDATORS && wxUSE_TEXTCTRL
28 #include "wx/textctrl.h"
29 #include "wx/combobox.h"
32 #include "wx/valnum.h"
33 #include "wx/numformatter.h"
35 // ============================================================================
36 // wxNumValidatorBase implementation
37 // ============================================================================
39 BEGIN_EVENT_TABLE(wxNumValidatorBase
, wxValidator
)
40 EVT_CHAR(wxNumValidatorBase::OnChar
)
41 EVT_KILL_FOCUS(wxNumValidatorBase::OnKillFocus
)
44 int wxNumValidatorBase::GetFormatFlags() const
46 int flags
= wxNumberFormatter::Style_None
;
47 if ( m_style
& wxNUM_VAL_THOUSANDS_SEPARATOR
)
48 flags
|= wxNumberFormatter::Style_WithThousandsSep
;
49 if ( m_style
& wxNUM_VAL_NO_TRAILING_ZEROES
)
50 flags
|= wxNumberFormatter::Style_NoTrailingZeroes
;
55 wxTextEntry
*wxNumValidatorBase::GetTextEntry() const
58 if ( wxTextCtrl
*text
= wxDynamicCast(m_validatorWindow
, wxTextCtrl
) )
60 #endif // wxUSE_TEXTCTRL
63 if ( wxComboBox
*combo
= wxDynamicCast(m_validatorWindow
, wxComboBox
) )
65 #endif // wxUSE_COMBOBOX
67 wxFAIL_MSG("Can only be used with wxTextCtrl or wxComboBox");
73 wxNumValidatorBase::GetCurrentValueAndInsertionPoint(wxString
& val
,
76 wxTextEntry
* const control
= GetTextEntry();
80 val
= control
->GetValue();
81 pos
= control
->GetInsertionPoint();
84 control
->GetSelection(&selFrom
, &selTo
);
86 const long selLen
= selTo
- selFrom
;
89 // Remove selected text because pressing a key would make it disappear.
90 val
.erase(selFrom
, selLen
);
92 // And adjust the insertion point to have correct position in the new
104 bool wxNumValidatorBase::IsMinusOk(const wxString
& val
, int pos
) const
106 // Minus is only ever accepted in the beginning of the string.
110 // And then only if there is no existing minus sign there.
111 if ( !val
.empty() && val
[0] == '-' )
117 void wxNumValidatorBase::OnChar(wxKeyEvent
& event
)
119 // By default we just validate this key so don't prevent the normal
120 // handling from taking place.
123 if ( !m_validatorWindow
)
127 const int ch
= event
.GetUnicodeKey();
128 if ( ch
== WXK_NONE
)
130 // It's a character without any Unicode equivalent at all, e.g. cursor
131 // arrow or function key, we never filter those.
134 #else // !wxUSE_UNICODE
135 const int ch
= event
.GetKeyCode();
136 if ( ch
> WXK_DELETE
)
138 // Not a character neither.
141 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
143 if ( ch
< WXK_SPACE
|| ch
== WXK_DELETE
)
145 // Allow ASCII control characters and Delete.
149 // Check if this character is allowed in the current state.
152 GetCurrentValueAndInsertionPoint(val
, pos
);
154 if ( !IsCharOk(val
, pos
, ch
) )
156 if ( !wxValidator::IsSilent() )
159 // Do not skip the event in this case, stop handling it here.
164 void wxNumValidatorBase::OnKillFocus(wxFocusEvent
& event
)
166 wxTextEntry
* const control
= GetTextEntry();
170 // When we change the control value below, its "modified" status is reset
171 // so we need to explicitly keep it marked as modified if it was so in the
174 // Notice that only wxTextCtrl (and not wxTextEntry) has
175 // IsModified()/MarkDirty() methods hence the need for dynamic cast.
176 wxTextCtrl
* const text
= wxDynamicCast(m_validatorWindow
, wxTextCtrl
);
177 const bool wasModified
= text
? text
->IsModified() : false;
179 control
->ChangeValue(NormalizeString(control
->GetValue()));
187 // ============================================================================
188 // wxIntegerValidatorBase implementation
189 // ============================================================================
191 wxString
wxIntegerValidatorBase::ToString(LongestValueType value
) const
193 return wxNumberFormatter::ToString(value
, GetFormatFlags());
197 wxIntegerValidatorBase::FromString(const wxString
& s
, LongestValueType
*value
)
199 return wxNumberFormatter::FromString(s
, value
);
203 wxIntegerValidatorBase::IsCharOk(const wxString
& val
, int pos
, wxChar ch
) const
205 // We may accept minus sign if we can represent negative numbers at all.
208 // Notice that entering '-' can make our value invalid, for example if
209 // we're limited to -5..15 range and the current value is 12, then the
210 // new value would be (invalid) -12. We consider it better to let the
211 // user do this because perhaps he is going to press Delete key next to
212 // make it -2 and forcing him to delete 1 first would be unnatural.
214 // TODO: It would be nice to indicate that the current control contents
215 // is invalid (if it's indeed going to be the case) once
216 // wxValidator supports doing this non-intrusively.
217 return m_min
< 0 && IsMinusOk(val
, pos
);
220 // We only accept digits here (remember that '-' is taken care of by the
221 // base class already).
222 if ( ch
< '0' || ch
> '9' )
225 // And the value after insertion needs to be in the defined range.
226 LongestValueType value
;
227 if ( !FromString(GetValueAfterInsertingChar(val
, pos
, ch
), &value
) )
230 return IsInRange(value
);
233 // ============================================================================
234 // wxFloatingPointValidatorBase implementation
235 // ============================================================================
237 wxString
wxFloatingPointValidatorBase::ToString(LongestValueType value
) const
239 return wxNumberFormatter::ToString(value
, m_precision
, GetFormatFlags());
243 wxFloatingPointValidatorBase::FromString(const wxString
& s
,
244 LongestValueType
*value
)
246 return wxNumberFormatter::FromString(s
, value
);
250 wxFloatingPointValidatorBase::IsCharOk(const wxString
& val
,
254 // We may accept minus sign if we can represent negative numbers at all.
256 return m_min
< 0 && IsMinusOk(val
, pos
);
258 const wxChar separator
= wxNumberFormatter::GetDecimalSeparator();
259 if ( ch
== separator
)
261 if ( val
.find(separator
) != wxString::npos
)
263 // There is already a decimal separator, can't insert another one.
267 // Prepending a separator before the minus sign isn't allowed.
268 if ( pos
== 0 && !val
.empty() && val
[0] == '-' )
271 // Otherwise always accept it, adding a decimal separator doesn't
272 // change the number value and, in particular, can't make it invalid.
273 // OTOH the checks below might not pass because strings like "." or
274 // "-." are not valid numbers so parsing them would fail, hence we need
275 // to treat it specially here.
279 // Must be a digit then.
280 if ( ch
< '0' || ch
> '9' )
283 // Check whether the value we'd obtain if we accepted this key is correct.
284 const wxString
newval(GetValueAfterInsertingChar(val
, pos
, ch
));
286 LongestValueType value
;
287 if ( !FromString(newval
, &value
) )
290 // Also check that it doesn't have too many decimal digits.
291 const size_t posSep
= newval
.find(separator
);
292 if ( posSep
!= wxString::npos
&& newval
.length() - posSep
- 1 > m_precision
)
295 // Finally check whether it is in the range.
296 return IsInRange(value
);
299 #endif // wxUSE_VALIDATORS && wxUSE_TEXTCTRL