From a54cf37118275c43cf03beb9a8960bba0d8a957c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 19 Jan 2011 10:48:28 +0000 Subject: [PATCH] Add wxIntegerValidator and wxFloatingPointValidator classes. Add validators for integer and floating point numbers. Add an example of their use to the validate sample as well as a new unit test and documentation for them. Use the new classes instead of wxTextValidator in wxGrid code. Closes #12166. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@66714 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- Makefile.in | 21 ++ build/bakefiles/files.bkl | 2 + build/msw/makefile.bcc | 28 ++ build/msw/makefile.gcc | 28 ++ build/msw/makefile.vc | 28 ++ build/msw/makefile.wat | 28 ++ build/msw/wx_core.dsp | 8 + build/msw/wx_vc7_core.vcproj | 6 + build/msw/wx_vc8_core.vcproj | 8 + build/msw/wx_vc9_core.vcproj | 8 + docs/changes.txt | 1 + docs/doxygen/mainpages/cat_classes.h | 2 + docs/doxygen/overviews/validator.h | 3 +- include/wx/valnum.h | 457 +++++++++++++++++++++++++++ interface/wx/valgen.h | 3 +- interface/wx/validate.h | 3 +- interface/wx/valnum.h | 346 ++++++++++++++++++++ interface/wx/valtext.h | 3 +- samples/validate/validate.cpp | 51 +++ samples/validate/validate.h | 7 + src/common/valnum.cpp | 299 ++++++++++++++++++ src/generic/grideditors.cpp | 6 +- tests/Makefile.in | 4 + tests/makefile.bcc | 4 + tests/makefile.gcc | 4 + tests/makefile.vc | 4 + tests/makefile.wat | 4 + tests/strings/numformatter.cpp | 13 +- tests/test.bkl | 1 + tests/test_test_gui.dsp | 4 + tests/test_vc7_test_gui.vcproj | 3 + tests/test_vc8_test_gui.vcproj | 4 + tests/test_vc9_test_gui.vcproj | 4 + tests/validators/valnum.cpp | 286 +++++++++++++++++ 34 files changed, 1665 insertions(+), 16 deletions(-) create mode 100644 include/wx/valnum.h create mode 100644 interface/wx/valnum.h create mode 100644 src/common/valnum.cpp create mode 100644 tests/validators/valnum.cpp diff --git a/Makefile.in b/Makefile.in index 74c5e06f2b..b1acf42689 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3933,6 +3933,7 @@ COND_USE_GUI_1_ALL_GUI_HEADERS = \ wx/toolbar.h \ wx/validate.h \ wx/valtext.h \ + wx/valnum.h \ wx/window.h \ wx/windowid.h \ wx/wrapsizer.h \ @@ -4592,6 +4593,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS = \ monodll_valgen.o \ monodll_validate.o \ monodll_valtext.o \ + monodll_valnum.o \ monodll_wincmn.o \ monodll_windowid.o \ monodll_wrapsizer.o \ @@ -4805,6 +4807,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS = \ monodll_valgen.o \ monodll_validate.o \ monodll_valtext.o \ + monodll_valnum.o \ monodll_wincmn.o \ monodll_windowid.o \ monodll_wrapsizer.o \ @@ -6502,6 +6505,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_1 = \ monolib_valgen.o \ monolib_validate.o \ monolib_valtext.o \ + monolib_valnum.o \ monolib_wincmn.o \ monolib_windowid.o \ monolib_wrapsizer.o \ @@ -6715,6 +6719,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_1 = \ monolib_valgen.o \ monolib_validate.o \ monolib_valtext.o \ + monolib_valnum.o \ monolib_wincmn.o \ monolib_windowid.o \ monolib_wrapsizer.o \ @@ -8596,6 +8601,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_2 = \ coredll_valgen.o \ coredll_validate.o \ coredll_valtext.o \ + coredll_valnum.o \ coredll_wincmn.o \ coredll_windowid.o \ coredll_wrapsizer.o \ @@ -8809,6 +8815,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_2 = \ coredll_valgen.o \ coredll_validate.o \ coredll_valtext.o \ + coredll_valnum.o \ coredll_wincmn.o \ coredll_windowid.o \ coredll_wrapsizer.o \ @@ -10168,6 +10175,7 @@ COND_USE_GUI_1_WXUNIV_0___CORE_SRC_OBJECTS_3 = \ corelib_valgen.o \ corelib_validate.o \ corelib_valtext.o \ + corelib_valnum.o \ corelib_wincmn.o \ corelib_windowid.o \ corelib_wrapsizer.o \ @@ -10381,6 +10389,7 @@ COND_USE_GUI_1_WXUNIV_1___CORE_SRC_OBJECTS_3 = \ corelib_valgen.o \ corelib_validate.o \ corelib_valtext.o \ + corelib_valnum.o \ corelib_wincmn.o \ corelib_windowid.o \ corelib_wrapsizer.o \ @@ -20059,6 +20068,9 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@monodll_valtext.o: $(srcdir)/src/common/valtext.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/valtext.cpp +@COND_USE_GUI_1@monodll_valnum.o: $(srcdir)/src/common/valnum.cpp $(MONODLL_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/valnum.cpp + @COND_USE_GUI_1@monodll_wincmn.o: $(srcdir)/src/common/wincmn.cpp $(MONODLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/wincmn.cpp @@ -25339,6 +25351,9 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@monolib_valtext.o: $(srcdir)/src/common/valtext.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/valtext.cpp +@COND_USE_GUI_1@monolib_valnum.o: $(srcdir)/src/common/valnum.cpp $(MONOLIB_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/valnum.cpp + @COND_USE_GUI_1@monolib_wincmn.o: $(srcdir)/src/common/wincmn.cpp $(MONOLIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/wincmn.cpp @@ -30799,6 +30814,9 @@ coredll_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@coredll_valtext.o: $(srcdir)/src/common/valtext.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/valtext.cpp +@COND_USE_GUI_1@coredll_valnum.o: $(srcdir)/src/common/valnum.cpp $(COREDLL_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/valnum.cpp + @COND_USE_GUI_1@coredll_wincmn.o: $(srcdir)/src/common/wincmn.cpp $(COREDLL_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/common/wincmn.cpp @@ -34762,6 +34780,9 @@ corelib_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@corelib_valtext.o: $(srcdir)/src/common/valtext.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/valtext.cpp +@COND_USE_GUI_1@corelib_valnum.o: $(srcdir)/src/common/valnum.cpp $(CORELIB_ODEP) +@COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/valnum.cpp + @COND_USE_GUI_1@corelib_wincmn.o: $(srcdir)/src/common/wincmn.cpp $(CORELIB_ODEP) @COND_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/common/wincmn.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 9d59f444d9..9c029fc6cb 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -766,6 +766,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/common/valgen.cpp src/common/validate.cpp src/common/valtext.cpp + src/common/valnum.cpp src/common/wincmn.cpp src/common/windowid.cpp src/common/wrapsizer.cpp @@ -909,6 +910,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/toolbar.h wx/validate.h wx/valtext.h + wx/valnum.h wx/window.h wx/windowid.h wx/wrapsizer.h diff --git a/build/msw/makefile.bcc b/build/msw/makefile.bcc index ca01770400..7f3d2ad4db 100644 --- a/build/msw/makefile.bcc +++ b/build/msw/makefile.bcc @@ -1905,6 +1905,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_valgen.obj \ $(OBJS)\monodll_validate.obj \ $(OBJS)\monodll_valtext.obj \ + $(OBJS)\monodll_valnum.obj \ $(OBJS)\monodll_wincmn.obj \ $(OBJS)\monodll_windowid.obj \ $(OBJS)\monodll_wrapsizer.obj \ @@ -2166,6 +2167,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_valgen.obj \ $(OBJS)\monodll_validate.obj \ $(OBJS)\monodll_valtext.obj \ + $(OBJS)\monodll_valnum.obj \ $(OBJS)\monodll_wincmn.obj \ $(OBJS)\monodll_windowid.obj \ $(OBJS)\monodll_wrapsizer.obj \ @@ -2659,6 +2661,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_valgen.obj \ $(OBJS)\monolib_validate.obj \ $(OBJS)\monolib_valtext.obj \ + $(OBJS)\monolib_valnum.obj \ $(OBJS)\monolib_wincmn.obj \ $(OBJS)\monolib_windowid.obj \ $(OBJS)\monolib_wrapsizer.obj \ @@ -2920,6 +2923,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_valgen.obj \ $(OBJS)\monolib_validate.obj \ $(OBJS)\monolib_valtext.obj \ + $(OBJS)\monolib_valnum.obj \ $(OBJS)\monolib_wincmn.obj \ $(OBJS)\monolib_windowid.obj \ $(OBJS)\monolib_wrapsizer.obj \ @@ -3301,6 +3305,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_valgen.obj \ $(OBJS)\coredll_validate.obj \ $(OBJS)\coredll_valtext.obj \ + $(OBJS)\coredll_valnum.obj \ $(OBJS)\coredll_wincmn.obj \ $(OBJS)\coredll_windowid.obj \ $(OBJS)\coredll_wrapsizer.obj \ @@ -3562,6 +3567,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_valgen.obj \ $(OBJS)\coredll_validate.obj \ $(OBJS)\coredll_valtext.obj \ + $(OBJS)\coredll_valnum.obj \ $(OBJS)\coredll_wincmn.obj \ $(OBJS)\coredll_windowid.obj \ $(OBJS)\coredll_wrapsizer.obj \ @@ -3832,6 +3838,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_valgen.obj \ $(OBJS)\corelib_validate.obj \ $(OBJS)\corelib_valtext.obj \ + $(OBJS)\corelib_valnum.obj \ $(OBJS)\corelib_wincmn.obj \ $(OBJS)\corelib_windowid.obj \ $(OBJS)\corelib_wrapsizer.obj \ @@ -4093,6 +4100,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_valgen.obj \ $(OBJS)\corelib_validate.obj \ $(OBJS)\corelib_valtext.obj \ + $(OBJS)\corelib_valnum.obj \ $(OBJS)\corelib_wincmn.obj \ $(OBJS)\corelib_windowid.obj \ $(OBJS)\corelib_wrapsizer.obj \ @@ -7816,6 +7824,11 @@ $(OBJS)\monodll_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\monodll_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\monodll_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif @@ -10141,6 +10154,11 @@ $(OBJS)\monolib_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\monolib_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\monolib_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif @@ -12460,6 +12478,11 @@ $(OBJS)\coredll_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\coredll_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\coredll_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif @@ -13840,6 +13863,11 @@ $(OBJS)\corelib_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\corelib_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\corelib_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc index f9d1a54671..0506d9d1f7 100644 --- a/build/msw/makefile.gcc +++ b/build/msw/makefile.gcc @@ -1916,6 +1916,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_valgen.o \ $(OBJS)\monodll_validate.o \ $(OBJS)\monodll_valtext.o \ + $(OBJS)\monodll_valnum.o \ $(OBJS)\monodll_wincmn.o \ $(OBJS)\monodll_windowid.o \ $(OBJS)\monodll_wrapsizer.o \ @@ -2179,6 +2180,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_valgen.o \ $(OBJS)\monodll_validate.o \ $(OBJS)\monodll_valtext.o \ + $(OBJS)\monodll_valnum.o \ $(OBJS)\monodll_wincmn.o \ $(OBJS)\monodll_windowid.o \ $(OBJS)\monodll_wrapsizer.o \ @@ -2676,6 +2678,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_valgen.o \ $(OBJS)\monolib_validate.o \ $(OBJS)\monolib_valtext.o \ + $(OBJS)\monolib_valnum.o \ $(OBJS)\monolib_wincmn.o \ $(OBJS)\monolib_windowid.o \ $(OBJS)\monolib_wrapsizer.o \ @@ -2939,6 +2942,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_valgen.o \ $(OBJS)\monolib_validate.o \ $(OBJS)\monolib_valtext.o \ + $(OBJS)\monolib_valnum.o \ $(OBJS)\monolib_wincmn.o \ $(OBJS)\monolib_windowid.o \ $(OBJS)\monolib_wrapsizer.o \ @@ -3334,6 +3338,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_valgen.o \ $(OBJS)\coredll_validate.o \ $(OBJS)\coredll_valtext.o \ + $(OBJS)\coredll_valnum.o \ $(OBJS)\coredll_wincmn.o \ $(OBJS)\coredll_windowid.o \ $(OBJS)\coredll_wrapsizer.o \ @@ -3597,6 +3602,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_valgen.o \ $(OBJS)\coredll_validate.o \ $(OBJS)\coredll_valtext.o \ + $(OBJS)\coredll_valnum.o \ $(OBJS)\coredll_wincmn.o \ $(OBJS)\coredll_windowid.o \ $(OBJS)\coredll_wrapsizer.o \ @@ -3873,6 +3879,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_valgen.o \ $(OBJS)\corelib_validate.o \ $(OBJS)\corelib_valtext.o \ + $(OBJS)\corelib_valnum.o \ $(OBJS)\corelib_wincmn.o \ $(OBJS)\corelib_windowid.o \ $(OBJS)\corelib_wrapsizer.o \ @@ -4136,6 +4143,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_valgen.o \ $(OBJS)\corelib_validate.o \ $(OBJS)\corelib_valtext.o \ + $(OBJS)\corelib_valnum.o \ $(OBJS)\corelib_wincmn.o \ $(OBJS)\corelib_windowid.o \ $(OBJS)\corelib_wrapsizer.o \ @@ -7966,6 +7974,11 @@ $(OBJS)\monodll_valtext.o: ../../src/common/valtext.cpp endif ifeq ($(USE_GUI),1) +$(OBJS)\monodll_valnum.o: ../../src/common/valnum.cpp + $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< +endif + +ifeq ($(USE_GUI),1) $(OBJS)\monodll_wincmn.o: ../../src/common/wincmn.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< endif @@ -10291,6 +10304,11 @@ $(OBJS)\monolib_valtext.o: ../../src/common/valtext.cpp endif ifeq ($(USE_GUI),1) +$(OBJS)\monolib_valnum.o: ../../src/common/valnum.cpp + $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< +endif + +ifeq ($(USE_GUI),1) $(OBJS)\monolib_wincmn.o: ../../src/common/wincmn.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< endif @@ -12610,6 +12628,11 @@ $(OBJS)\coredll_valtext.o: ../../src/common/valtext.cpp endif ifeq ($(USE_GUI),1) +$(OBJS)\coredll_valnum.o: ../../src/common/valnum.cpp + $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< +endif + +ifeq ($(USE_GUI),1) $(OBJS)\coredll_wincmn.o: ../../src/common/wincmn.cpp $(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $< endif @@ -13990,6 +14013,11 @@ $(OBJS)\corelib_valtext.o: ../../src/common/valtext.cpp endif ifeq ($(USE_GUI),1) +$(OBJS)\corelib_valnum.o: ../../src/common/valnum.cpp + $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< +endif + +ifeq ($(USE_GUI),1) $(OBJS)\corelib_wincmn.o: ../../src/common/wincmn.cpp $(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $< endif diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc index 322a1bfe3b..395efdab18 100644 --- a/build/msw/makefile.vc +++ b/build/msw/makefile.vc @@ -2113,6 +2113,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_valgen.obj \ $(OBJS)\monodll_validate.obj \ $(OBJS)\monodll_valtext.obj \ + $(OBJS)\monodll_valnum.obj \ $(OBJS)\monodll_wincmn.obj \ $(OBJS)\monodll_windowid.obj \ $(OBJS)\monodll_wrapsizer.obj \ @@ -2374,6 +2375,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = \ $(OBJS)\monodll_valgen.obj \ $(OBJS)\monodll_validate.obj \ $(OBJS)\monodll_valtext.obj \ + $(OBJS)\monodll_valnum.obj \ $(OBJS)\monodll_wincmn.obj \ $(OBJS)\monodll_windowid.obj \ $(OBJS)\monodll_wrapsizer.obj \ @@ -2873,6 +2875,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_valgen.obj \ $(OBJS)\monolib_validate.obj \ $(OBJS)\monolib_valtext.obj \ + $(OBJS)\monolib_valnum.obj \ $(OBJS)\monolib_wincmn.obj \ $(OBJS)\monolib_windowid.obj \ $(OBJS)\monolib_wrapsizer.obj \ @@ -3134,6 +3137,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = \ $(OBJS)\monolib_valgen.obj \ $(OBJS)\monolib_validate.obj \ $(OBJS)\monolib_valtext.obj \ + $(OBJS)\monolib_valnum.obj \ $(OBJS)\monolib_wincmn.obj \ $(OBJS)\monolib_windowid.obj \ $(OBJS)\monolib_wrapsizer.obj \ @@ -3581,6 +3585,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_valgen.obj \ $(OBJS)\coredll_validate.obj \ $(OBJS)\coredll_valtext.obj \ + $(OBJS)\coredll_valnum.obj \ $(OBJS)\coredll_wincmn.obj \ $(OBJS)\coredll_windowid.obj \ $(OBJS)\coredll_wrapsizer.obj \ @@ -3842,6 +3847,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = \ $(OBJS)\coredll_valgen.obj \ $(OBJS)\coredll_validate.obj \ $(OBJS)\coredll_valtext.obj \ + $(OBJS)\coredll_valnum.obj \ $(OBJS)\coredll_wincmn.obj \ $(OBJS)\coredll_windowid.obj \ $(OBJS)\coredll_wrapsizer.obj \ @@ -4118,6 +4124,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_valgen.obj \ $(OBJS)\corelib_validate.obj \ $(OBJS)\corelib_valtext.obj \ + $(OBJS)\corelib_valnum.obj \ $(OBJS)\corelib_wincmn.obj \ $(OBJS)\corelib_windowid.obj \ $(OBJS)\corelib_wrapsizer.obj \ @@ -4379,6 +4386,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = \ $(OBJS)\corelib_valgen.obj \ $(OBJS)\corelib_validate.obj \ $(OBJS)\corelib_valtext.obj \ + $(OBJS)\corelib_valnum.obj \ $(OBJS)\corelib_wincmn.obj \ $(OBJS)\corelib_windowid.obj \ $(OBJS)\corelib_wrapsizer.obj \ @@ -8396,6 +8404,11 @@ $(OBJS)\monodll_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\monodll_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\monodll_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif @@ -10721,6 +10734,11 @@ $(OBJS)\monolib_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\monolib_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\monolib_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif @@ -13040,6 +13058,11 @@ $(OBJS)\coredll_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\coredll_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\coredll_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif @@ -14420,6 +14443,11 @@ $(OBJS)\corelib_valtext.obj: ..\..\src\common\valtext.cpp !endif !if "$(USE_GUI)" == "1" +$(OBJS)\corelib_valnum.obj: ..\..\src\common\valnum.cpp + $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\valnum.cpp +!endif + +!if "$(USE_GUI)" == "1" $(OBJS)\corelib_wincmn.obj: ..\..\src\common\wincmn.cpp $(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\common\wincmn.cpp !endif diff --git a/build/msw/makefile.wat b/build/msw/makefile.wat index 86cd7fdcf9..0b32d6b439 100644 --- a/build/msw/makefile.wat +++ b/build/msw/makefile.wat @@ -467,6 +467,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = & $(OBJS)\monodll_valgen.obj & $(OBJS)\monodll_validate.obj & $(OBJS)\monodll_valtext.obj & + $(OBJS)\monodll_valnum.obj & $(OBJS)\monodll_wincmn.obj & $(OBJS)\monodll_windowid.obj & $(OBJS)\monodll_wrapsizer.obj & @@ -730,6 +731,7 @@ ____CORE_SRC_FILENAMES_OBJECTS = & $(OBJS)\monodll_valgen.obj & $(OBJS)\monodll_validate.obj & $(OBJS)\monodll_valtext.obj & + $(OBJS)\monodll_valnum.obj & $(OBJS)\monodll_wincmn.obj & $(OBJS)\monodll_windowid.obj & $(OBJS)\monodll_wrapsizer.obj & @@ -1232,6 +1234,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = & $(OBJS)\monolib_valgen.obj & $(OBJS)\monolib_validate.obj & $(OBJS)\monolib_valtext.obj & + $(OBJS)\monolib_valnum.obj & $(OBJS)\monolib_wincmn.obj & $(OBJS)\monolib_windowid.obj & $(OBJS)\monolib_wrapsizer.obj & @@ -1495,6 +1498,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS = & $(OBJS)\monolib_valgen.obj & $(OBJS)\monolib_validate.obj & $(OBJS)\monolib_valtext.obj & + $(OBJS)\monolib_valnum.obj & $(OBJS)\monolib_wincmn.obj & $(OBJS)\monolib_windowid.obj & $(OBJS)\monolib_wrapsizer.obj & @@ -1901,6 +1905,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = & $(OBJS)\coredll_valgen.obj & $(OBJS)\coredll_validate.obj & $(OBJS)\coredll_valtext.obj & + $(OBJS)\coredll_valnum.obj & $(OBJS)\coredll_wincmn.obj & $(OBJS)\coredll_windowid.obj & $(OBJS)\coredll_wrapsizer.obj & @@ -2164,6 +2169,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS = & $(OBJS)\coredll_valgen.obj & $(OBJS)\coredll_validate.obj & $(OBJS)\coredll_valtext.obj & + $(OBJS)\coredll_valnum.obj & $(OBJS)\coredll_wincmn.obj & $(OBJS)\coredll_windowid.obj & $(OBJS)\coredll_wrapsizer.obj & @@ -2442,6 +2448,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = & $(OBJS)\corelib_valgen.obj & $(OBJS)\corelib_validate.obj & $(OBJS)\corelib_valtext.obj & + $(OBJS)\corelib_valnum.obj & $(OBJS)\corelib_wincmn.obj & $(OBJS)\corelib_windowid.obj & $(OBJS)\corelib_wrapsizer.obj & @@ -2705,6 +2712,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS = & $(OBJS)\corelib_valgen.obj & $(OBJS)\corelib_validate.obj & $(OBJS)\corelib_valtext.obj & + $(OBJS)\corelib_valnum.obj & $(OBJS)\corelib_wincmn.obj & $(OBJS)\corelib_windowid.obj & $(OBJS)\corelib_wrapsizer.obj & @@ -8225,6 +8233,11 @@ $(OBJS)\monodll_valtext.obj : .AUTODEPEND ..\..\src\common\valtext.cpp !endif !ifeq USE_GUI 1 +$(OBJS)\monodll_valnum.obj : .AUTODEPEND ..\..\src\common\valnum.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(MONODLL_CXXFLAGS) $< +!endif + +!ifeq USE_GUI 1 $(OBJS)\monodll_wincmn.obj : .AUTODEPEND ..\..\src\common\wincmn.cpp $(CXX) -bt=nt -zq -fo=$^@ $(MONODLL_CXXFLAGS) $< !endif @@ -10550,6 +10563,11 @@ $(OBJS)\monolib_valtext.obj : .AUTODEPEND ..\..\src\common\valtext.cpp !endif !ifeq USE_GUI 1 +$(OBJS)\monolib_valnum.obj : .AUTODEPEND ..\..\src\common\valnum.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(MONOLIB_CXXFLAGS) $< +!endif + +!ifeq USE_GUI 1 $(OBJS)\monolib_wincmn.obj : .AUTODEPEND ..\..\src\common\wincmn.cpp $(CXX) -bt=nt -zq -fo=$^@ $(MONOLIB_CXXFLAGS) $< !endif @@ -12869,6 +12887,11 @@ $(OBJS)\coredll_valtext.obj : .AUTODEPEND ..\..\src\common\valtext.cpp !endif !ifeq USE_GUI 1 +$(OBJS)\coredll_valnum.obj : .AUTODEPEND ..\..\src\common\valnum.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(COREDLL_CXXFLAGS) $< +!endif + +!ifeq USE_GUI 1 $(OBJS)\coredll_wincmn.obj : .AUTODEPEND ..\..\src\common\wincmn.cpp $(CXX) -bt=nt -zq -fo=$^@ $(COREDLL_CXXFLAGS) $< !endif @@ -14249,6 +14272,11 @@ $(OBJS)\corelib_valtext.obj : .AUTODEPEND ..\..\src\common\valtext.cpp !endif !ifeq USE_GUI 1 +$(OBJS)\corelib_valnum.obj : .AUTODEPEND ..\..\src\common\valnum.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(CORELIB_CXXFLAGS) $< +!endif + +!ifeq USE_GUI 1 $(OBJS)\corelib_wincmn.obj : .AUTODEPEND ..\..\src\common\wincmn.cpp $(CXX) -bt=nt -zq -fo=$^@ $(CORELIB_CXXFLAGS) $< !endif diff --git a/build/msw/wx_core.dsp b/build/msw/wx_core.dsp index 233278896e..8fafe98019 100644 --- a/build/msw/wx_core.dsp +++ b/build/msw/wx_core.dsp @@ -730,6 +730,10 @@ SOURCE=..\..\src\common\validate.cpp # End Source File # Begin Source File +SOURCE=..\..\src\common\valnum.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\common\valtext.cpp # End Source File # Begin Source File @@ -6797,6 +6801,10 @@ SOURCE=..\..\include\wx\validate.h # End Source File # Begin Source File +SOURCE=..\..\include\wx\valnum.h +# End Source File +# Begin Source File + SOURCE=..\..\include\wx\valtext.h # End Source File # Begin Source File diff --git a/build/msw/wx_vc7_core.vcproj b/build/msw/wx_vc7_core.vcproj index 1af35ea21e..f06e630c33 100644 --- a/build/msw/wx_vc7_core.vcproj +++ b/build/msw/wx_vc7_core.vcproj @@ -940,6 +940,9 @@ RelativePath="..\..\src\common\validate.cpp"> + + + + + + @@ -7608,6 +7612,10 @@ > + + diff --git a/build/msw/wx_vc9_core.vcproj b/build/msw/wx_vc9_core.vcproj index d007bd54f5..8113db4af9 100644 --- a/build/msw/wx_vc9_core.vcproj +++ b/build/msw/wx_vc9_core.vcproj @@ -1283,6 +1283,10 @@ > + + @@ -7604,6 +7608,10 @@ > + + diff --git a/docs/changes.txt b/docs/changes.txt index b1efe24315..0e564f755a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -423,6 +423,7 @@ All: - Added negatable command line switches (Armel Asselin). - Added wxVersionInfo and various GetLibraryVersionInfo() functions (troelsk). - Added wxNumberFormatter for dealing with thousands separators. +- Added wxIntegerValidator<> and wxFloatingPointValidator<> validators. Unix: diff --git a/docs/doxygen/mainpages/cat_classes.h b/docs/doxygen/mainpages/cat_classes.h index 282cbdadc5..c1a895e057 100644 --- a/docs/doxygen/mainpages/cat_classes.h +++ b/docs/doxygen/mainpages/cat_classes.h @@ -208,6 +208,8 @@ Related Overviews: @ref overview_validator @li wxValidator: Base validator class @li wxTextValidator: Text control validator class @li wxGenericValidator: Generic control validator class +@li wxIntegerValidator: Text control validator class for integer numbers +@li wxFloatingPointValidator: Text control validator class for floating point numbers diff --git a/docs/doxygen/overviews/validator.h b/docs/doxygen/overviews/validator.h index 42038a6d1f..81010b915f 100644 --- a/docs/doxygen/overviews/validator.h +++ b/docs/doxygen/overviews/validator.h @@ -10,7 +10,8 @@ @page overview_validator wxValidator Overview -Classes: wxValidator, wxTextValidator, wxGenericValidator +Classes: wxValidator, wxTextValidator, wxGenericValidator, wxIntegerValidator, +wxFloatingPointValidator @li @ref overview_validator_intro @li @ref overview_validator_anatomy diff --git a/include/wx/valnum.h b/include/wx/valnum.h new file mode 100644 index 0000000000..428fe7ff8a --- /dev/null +++ b/include/wx/valnum.h @@ -0,0 +1,457 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/valnum.h +// Purpose: Numeric validator classes. +// Author: Vadim Zeitlin based on the submission of Fulvio Senore +// Created: 2010-11-06 +// Copyright: (c) 2010 wxWidgets team +// (c) 2011 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_VALNUM_H_ +#define _WX_VALNUM_H_ + +#include "wx/defs.h" + +#if wxUSE_VALIDATORS + +#include "wx/validate.h" + +#include + +// Bit masks used for numeric validator styles. +enum wxNumValidatorStyle +{ + wxNUM_VAL_DEFAULT = 0x0, + wxNUM_VAL_THOUSANDS_SEPARATOR = 0x1, + wxNUM_VAL_ZERO_AS_BLANK = 0x2, + wxNUM_VAL_NO_TRAILING_ZEROES = 0x4 +}; + +// ---------------------------------------------------------------------------- +// Base class for all numeric validators. +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxNumValidatorBase : public wxValidator +{ +public: + // Change the validator style. Usually it's specified during construction. + void SetStyle(int style) { m_style = style; } + + + // Override base class method to not do anything but always return success: + // we don't need this as we do our validation on the fly here. + virtual bool Validate(wxWindow * WXUNUSED(parent)) { return true; } + +protected: + wxNumValidatorBase(int style) + { + m_style = style; + } + + wxNumValidatorBase(const wxNumValidatorBase& other) + { + m_style = other.m_style; + } + + bool HasFlag(wxNumValidatorStyle style) const + { + return (m_style & style) != 0; + } + + // Get the text entry of the associated control. Normally shouldn't ever + // return NULL (and will assert if it does return it) but the caller should + // still test the return value for safety. + wxTextEntry *GetTextEntry() const; + + // Convert wxNUM_VAL_THOUSANDS_SEPARATOR and wxNUM_VAL_NO_TRAILING_ZEROES + // bits of our style to the corresponding wxNumberFormatter::Style values. + int GetFormatFlags() const; + + // Return true if pressing a '-' key is acceptable for the current control + // contents and insertion point. This is meant to be called from the + // derived class IsCharOk() implementation. + bool IsMinusOk(const wxString& val, int pos) const; + + // Return the string which would result from inserting the given character + // at the specified position. + wxString GetValueAfterInsertingChar(wxString val, int pos, wxChar ch) const + { + val.insert(pos, ch); + return val; + } + +private: + // Check whether the specified character can be inserted in the control at + // the given position in the string representing the current controls + // contents. + // + // Notice that the base class checks for '-' itself so it's never passed to + // this function. + virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const = 0; + + // NormalizeString the contents of the string if it's a valid number, return + // empty string otherwise. + virtual wxString NormalizeString(const wxString& s) const = 0; + + + // Event handlers. + void OnChar(wxKeyEvent& event); + void OnKillFocus(wxFocusEvent& event); + + + // Determine the current insertion point and text in the associated control. + void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const; + + + // Combination of wxVAL_NUM_XXX values. + int m_style; + + + wxDECLARE_EVENT_TABLE(); + + wxDECLARE_NO_ASSIGN_CLASS(wxNumValidatorBase); +}; + +namespace wxPrivate +{ + +// This is a helper class used by wxIntegerValidator and wxFloatingPointValidator +// below that implements Transfer{To,From}Window() adapted to the type of the +// variable. +// +// The template argument B is the name of the base class which must derive from +// wxNumValidatorBase and define LongestValueType type and {To,As}String() +// methods i.e. basically be one of wx{Integer,Number}ValidatorBase classes. +// +// The template argument T is just the type handled by the validator that will +// inherit from this one. +template +class wxNumValidator : public B +{ +public: + typedef B BaseValidator; + typedef T ValueType; + + typedef typename BaseValidator::LongestValueType LongestValueType; + + wxCOMPILE_TIME_ASSERT + ( + sizeof(ValueType) <= sizeof(LongestValueType), + UnsupportedType + ); + + void SetMin(ValueType min) + { + this->DoSetMin(min); + } + + void SetMax(ValueType max) + { + this->DoSetMax(max); + } + + void SetRange(ValueType min, ValueType max) + { + SetMin(min); + SetMax(max); + } + + virtual bool TransferToWindow() + { + if ( m_value ) + { + wxTextEntry * const control = BaseValidator::GetTextEntry(); + if ( !control ) + return false; + + control->SetValue(NormalizeValue(*m_value)); + } + + return true; + } + + virtual bool TransferFromWindow() + { + if ( m_value ) + { + wxTextEntry * const control = BaseValidator::GetTextEntry(); + if ( !control ) + return false; + + const wxString s(control->GetValue()); + LongestValueType value; + if ( s.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) ) + value = 0; + else if ( !BaseValidator::FromString(s, &value) ) + return false; + + if ( !IsInRange(value) ) + return false; + + *m_value = static_cast(value); + } + + return true; + } + +protected: + wxNumValidator(ValueType *value, int style) + : BaseValidator(style), + m_value(value) + { + } + + // Implement wxNumValidatorBase virtual method which is the same for + // both integer and floating point numbers. + virtual wxString NormalizeString(const wxString& s) const + { + LongestValueType value; + return BaseValidator::FromString(s, &value) ? NormalizeValue(value) + : wxString(); + } + +private: + // Just a helper which is a common part of TransferToWindow() and + // NormalizeString(): returns string representation of a number honouring + // wxNUM_VAL_ZERO_AS_BLANK flag. + wxString NormalizeValue(LongestValueType value) const + { + wxString s; + if ( value != 0 || !BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) ) + s = ToString(value); + + return s; + } + + + ValueType * const m_value; + + wxDECLARE_NO_ASSIGN_CLASS(wxNumValidator); +}; + +} // namespace wxPrivate + +// ---------------------------------------------------------------------------- +// Validators for integer numbers. +// ---------------------------------------------------------------------------- + +// Base class for integer numbers validator. This class contains all non +// type-dependent code of wxIntegerValidator<> and always works with values of +// type LongestValueType. It is not meant to be used directly, please use +// wxIntegerValidator<> only instead. +class WXDLLIMPEXP_CORE wxIntegerValidatorBase : public wxNumValidatorBase +{ +protected: + // Define the type we use here, it should be the maximal-sized integer type + // we support to make it possible to base wxIntegerValidator<> for any type + // on it. +#ifdef wxLongLong_t + typedef wxLongLong_t LongestValueType; +#else + typedef long LongestValueType; +#endif + + wxIntegerValidatorBase(int style) + : wxNumValidatorBase(style) + { + wxASSERT_MSG( !(style & wxNUM_VAL_NO_TRAILING_ZEROES), + "This style doesn't make sense for integers." ); + } + + wxIntegerValidatorBase(const wxIntegerValidatorBase& other) + : wxNumValidatorBase(other) + { + m_min = other.m_min; + m_max = other.m_max; + } + + // Provide methods for wxNumValidator use. + wxString ToString(LongestValueType value) const; + static bool FromString(const wxString& s, LongestValueType *value); + + void DoSetMin(LongestValueType min) { m_min = min; } + void DoSetMax(LongestValueType max) { m_max = max; } + + bool IsInRange(LongestValueType value) const + { + return m_min <= value && value <= m_max; + } + + // Implement wxNumValidatorBase pure virtual method. + virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const; + +private: + // Minimal and maximal values accepted (inclusive). + LongestValueType m_min, m_max; + + wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidatorBase); +}; + +// Validator for integer numbers. It can actually work with any integer type +// (short, int or long and long long if supported) and their unsigned versions +// as well. +template +class wxIntegerValidator + : public wxPrivate::wxNumValidator +{ +public: + typedef T ValueType; + + typedef + wxPrivate::wxNumValidator Base; + + // Ctor for an integer validator. + // + // Sets the range appropriately for the type, including setting 0 as the + // minimal value for the unsigned types. + wxIntegerValidator(ValueType *value = NULL, int style = wxNUM_VAL_DEFAULT) + : Base(value, style) + { + DoSetMin(std::numeric_limits::min()); + DoSetMax(std::numeric_limits::max()); + } + + virtual wxObject *Clone() const { return new wxIntegerValidator(*this); } + +private: + wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidator); +}; + +// Helper function for creating integer validators which allows to avoid +// explicitly specifying the type as it deduces it from its parameter. +template +inline wxIntegerValidator +wxMakeIntegerValidator(T *value, int style = wxNUM_VAL_DEFAULT) +{ + return wxIntegerValidator(value, style); +} + +// ---------------------------------------------------------------------------- +// Validators for floating point numbers. +// ---------------------------------------------------------------------------- + +// Similar to wxIntegerValidatorBase, this class is not meant to be used +// directly, only wxFloatingPointValidator<> should be used in the user code. +class WXDLLIMPEXP_CORE wxFloatingPointValidatorBase : public wxNumValidatorBase +{ +public: + // Set precision i.e. the number of digits shown (and accepted on input) + // after the decimal point. By default this is set to the maximal precision + // supported by the type handled by the validator. + void SetPrecision(unsigned precision) { m_precision = precision; } + +protected: + // Notice that we can't use "long double" here because it's not supported + // by wxNumberFormatter yet, so restrict ourselves to just double (and + // float). + typedef double LongestValueType; + + wxFloatingPointValidatorBase(int style) + : wxNumValidatorBase(style) + { + } + + wxFloatingPointValidatorBase(const wxFloatingPointValidatorBase& other) + : wxNumValidatorBase(other) + { + m_precision = other.m_precision; + + m_min = other.m_min; + m_max = other.m_max; + } + + // Provide methods for wxNumValidator use. + wxString ToString(LongestValueType value) const; + static bool FromString(const wxString& s, LongestValueType *value); + + void DoSetMin(LongestValueType min) { m_min = min; } + void DoSetMax(LongestValueType max) { m_max = max; } + + bool IsInRange(LongestValueType value) const + { + return m_min <= value && value <= m_max; + } + + // Implement wxNumValidatorBase pure virtual method. + virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const; + +private: + // Maximum number of decimals digits after the decimal separator. + unsigned m_precision; + + // Minimal and maximal values accepted (inclusive). + LongestValueType m_min, m_max; + + wxDECLARE_NO_ASSIGN_CLASS(wxFloatingPointValidatorBase); +}; + +// Validator for floating point numbers. It can be used with float, double or +// long double values. +template +class wxFloatingPointValidator + : public wxPrivate::wxNumValidator +{ +public: + typedef T ValueType; + typedef wxPrivate::wxNumValidator Base; + + // Ctor using implicit (maximal) precision for this type. + wxFloatingPointValidator(ValueType *value = NULL, + int style = wxNUM_VAL_DEFAULT) + : Base(value, style) + { + DoSetMinMax(); + + SetPrecision(std::numeric_limits::digits10); + } + + // Ctor specifying an explicit precision. + wxFloatingPointValidator(int precision, + ValueType *value = NULL, + int style = wxNUM_VAL_DEFAULT) + : Base(value, style) + { + DoSetMinMax(); + + this->SetPrecision(precision); + } + + virtual wxObject *Clone() const + { + return new wxFloatingPointValidator(*this); + } + +private: + void DoSetMinMax() + { + // NB: Do not use min(), it's not the smallest representable value for + // the floating point types but rather the smallest representable + // positive value. + DoSetMin(-std::numeric_limits::max()); + DoSetMax( std::numeric_limits::max()); + } +}; + +// Helper similar to wxMakeIntValidator(). +// +// NB: Unfortunately we can't just have a wxMakeNumericValidator() which would +// return either wxIntegerValidator<> or wxFloatingPointValidator<> so we +// do need two different functions. +template +inline wxFloatingPointValidator +wxMakeFloatingPointValidator(T *value, int style = wxNUM_VAL_DEFAULT) +{ + return wxFloatingPointValidator(value, style); +} + +template +inline wxFloatingPointValidator +wxMakeFloatingPointValidator(int precision, T *value, int style = wxNUM_VAL_DEFAULT) +{ + return wxFloatingPointValidator(precision, value, style); +} + +#endif // wxUSE_VALIDATORS + +#endif // _WX_VALNUM_H_ diff --git a/interface/wx/valgen.h b/interface/wx/valgen.h index cc2a6962a5..9a4dc6b45b 100644 --- a/interface/wx/valgen.h +++ b/interface/wx/valgen.h @@ -27,7 +27,8 @@ @library{wxcore} @category{validator} - @see @ref overview_validator, wxValidator, wxTextValidator + @see @ref overview_validator, wxValidator, wxTextValidator, + wxIntegerValidator, wxFloatingPointValidator */ class wxGenericValidator : public wxValidator { diff --git a/interface/wx/validate.h b/interface/wx/validate.h index bdbe3aeea4..fcaa6a76cb 100644 --- a/interface/wx/validate.h +++ b/interface/wx/validate.h @@ -38,7 +38,8 @@ @stdobjects ::wxDefaultValidator - @see @ref overview_validator, wxTextValidator, wxGenericValidator + @see @ref overview_validator, wxTextValidator, wxGenericValidator, + wxIntegerValidator, wxFloatingPointValidator */ class wxValidator : public wxEvtHandler { diff --git a/interface/wx/valnum.h b/interface/wx/valnum.h new file mode 100644 index 0000000000..56268d3647 --- /dev/null +++ b/interface/wx/valnum.h @@ -0,0 +1,346 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/valnum.h +// Purpose: Documentation of numeric validator classes. +// Author: Vadim Zeitlin based on the submission of Fulvio Senore +// Created: 2010-11-06 +// Copyright: (c) 2010 wxWidgets team +// (c) 2011 Vadim Zeitlin +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +/** + Bit masks used for numeric validator styles. + + A combination of these flags can be used when creating wxIntegerValidator + and wxFloatingPointValidator objects and with their SetStyle() methods. + + @since 2.9.2 + @category{validator} + */ +enum wxNumValidatorStyle +{ + /** + Indicates absence of any other flags. + + This value corresponds to the default behaviour. + */ + wxNUM_VAL_DEFAULT = 0, + + /** + Use thousands separators in the numbers. + + When this style is used, numbers are formatted using the thousands + separators after validating the user entry (if the current locale uses + the thousands separators character). + */ + wxNUM_VAL_THOUSANDS_SEPARATOR = 1, + + /** + Show a value of zero as an empty string. + + With this style a value of zero in the associated variable is + translated to an empty string and an empty value of the control is + translated to a value of zero. + */ + wxNUM_VAL_ZERO_AS_BLANK = 2, + + /** + Remove trailing zeroes from the fractional part of the number. + + This style can only be used with wxFloatingPointValidator and indicates + that trailing zeroes should be removed from the control text when it is + validated. By default, as many zeroes as needed to satisfy the + precision used when creating the validator will be appended. + + For example, without this style a wxFloatingPointValidator with a + precision 3 will show the value of 1.5 as "1.500" after validation. + With this style, the value will be shown as just "1.5" (while a value + of e.g. 1.567 will still be shown with all the three significant + digits, of course). + */ + wxNUM_VAL_NO_TRAILING_ZEROES + +}; + +/** + wxNumValidator is the common base class for numeric validator classes. + + This class is never used directly, but only as a base class for + wxIntegerValidator and wxFloatingPointValidator. + + @tparam T + Type of the values used with this validator. + + @category{validator} + + @since 2.9.2 + */ +template +class wxNumValidator : public wxValidator +{ +public: + /// Type of the values this validator is used with. + typedef T ValueType; + + /** + Sets the minimal value accepted by the validator. + + This value is inclusive, i.e. the value equal to @a min is accepted. + */ + void SetMin(ValueType min); + + /** + Sets the maximal value accepted by the validator. + + This value is inclusive, i.e. the value equal to @a max is accepted. + */ + void SetMax(ValueType max); + + /** + Sets both minimal and maximal values accepted by the validator. + + Calling this is equivalent to calling both SetMin() and SetMax(). + */ + void SetRange(ValueType min, ValueType max) + + + /** + Change the validator style. + + Can be used to change the style of the validator after its creation. + The @a style parameter must be a combination of the values from + wxNumValidatorStyle enum. + */ + void SetStyle(int style); + + + /** + Override base class method to format the control contents. + + This method is called when the associated window is shown and it fills + it with the contents of the associated variable, if any, formatted + according to the validator style. + + It does nothing if there is no associated variable. + */ + virtual bool TransferToWindow(); + + /** + Override base class method to validate the control contents. + + This method is called to check the correctness of user input and fill + the associated variable with the controls numeric value. It returns + false if it is not a number in the configured range or if the control + contents is empty for a validator without wxNUM_VAL_ZERO_AS_BLANK + style. + + It does nothing if there is no associated variable. + */ + virtual bool TransferFromWindow(); +}; + +/** + Validator for text entries used for integer entry. + + This validator can be used with wxTextCtrl or wxComboBox (and potentially + any other class implementing wxTextEntry interface) to check that only + valid integer values can be entered into them. + + This is a template class which can be instantiated for all the integer types + (i.e. @c short, @c int, @c long and long long if available) as + well as their unsigned versions. + + By default this validator accepts any integer values in the range + appropriate for its type, e.g. INT_MIN..INT_MAX for @c int or + 0..USHRT_MAX for unsigned short. This range can + be restricted further by calling SetMin() and SetMax() or SetRange() + methods inherited from the base class. + + A simple example of using this class: + @code + class MyDialog : public wxDialog + { + public: + MyDialog() + { + ... + // Allow positive integers and display them with thousands + // separators. + wxIntegerValidator + val(&m_value, wxNUM_VAL_THOUSANDS_SEPARATOR); + + // If the variable were of type "long" and not "unsigned long" + // we would have needed to call val.SetMin(0) but as it is, + // this is not needed. + + // Associate it with the text control: + new wxTextCtrl(this, ..., val); + } + + private: + unsigned long m_value; + }; + @endcode + For more information, please see @ref overview_validator. + + @library{wxcore} + @category{validator} + + @see @ref overview_validator, wxValidator, wxGenericValidator, + wxTextValidator, wxMakeIntegerValidator() + + @since 2.9.2 +*/ +template +class wxIntegerValidator : public wxNumValidator +{ +public: + /// Type of the values this validator is used with. + typedef T ValueType; + + /** + Validator constructor. + + @param value + A pointer to the variable associated with the validator. If non + @NULL, this variable should have a lifetime equal to or longer than + the validator lifetime (which is usually determined by the lifetime + of the window). + @param style + A combination of wxNumValidatorStyle enum values with the exception + of wxNUM_VAL_NO_TRAILING_ZEROES which can't be used here. + */ + wxIntegerValidator(ValueType *value = NULL, int style = wxNUM_VAL_DEFAULT); +}; + +/** + Creates a wxIntegerValidator object with automatic type deduction. + + This function can be used to create wxIntegerValidator object without + explicitly specifying its type, e.g. write just: + @code + new wxTextCtrl(..., wxMakeIntegerValidator(&m_var)); + @endcode + instead of more verbose + @code + new wxTextCtrl(..., wxIntegerValidator(&m_var)); + @endcode + + @since 2.9.2 + */ +template +wxIntegerValidator +wxMakeIntegerValidator(T *value, int style = wxNUM_VAL_DEFAULT); + +/** + Validator for text entries used for floating point numbers entry. + + This validator can be used with wxTextCtrl or wxComboBox (and potentially + any other class implementing wxTextEntry interface) to check that only + valid floating point values can be entered into them. Currently only fixed + format is supported on input, i.e. scientific format with mantissa and + exponent is not supported. + + This template class can be instantiated for either @c float or @c double, + long double values are not currently supported. + + Similarly to wxIntegerValidator<>, the range for the accepted values is by + default set appropriately for the type. Additionally, this validator allows + to specify the maximum number of digits that can be entered after the + decimal separator. By default this is also set appropriately for the type + used, e.g. 6 for @c float and 15 for @c double on a typical IEEE-754-based + implementation. As with the range, the precision can be restricted after + the validator creation if necessary. + + A simple example of using this class: + @code + class MyDialog : public wxDialog + { + public: + MyDialog() + { + ... + // Allow floating point numbers from 0 to 100 with 2 decimal + // digits only and handle empty string as 0 by default. + wxFloatingPointValidator + val(2, &m_value, wxNUM_VAL_ZERO_AS_BLANK); + val.SetRange(0, 100); + + // Associate it with the text control: + new wxTextCtrl(this, ..., val); + } + + private: + float m_value; + }; + @endcode + + For more information, please see @ref overview_validator. + + @library{wxcore} + @category{validator} + + @see @ref overview_validator, wxValidator, wxGenericValidator, + wxTextValidator, wxMakeIntegerValidator() + + @since 2.9.2 +*/ +template +class wxFloatingPointValidator : public wxNumValidator +{ +public: + /// Type of the values this validator is used with. + typedef T ValueType; + + /** + Validator constructor. + + @param value + A pointer to the variable associated with the validator. If non + @NULL, this variable should have a lifetime equal to or longer than + the validator lifetime (which is usually determined by the lifetime + of the window). + @param style + A combination of wxNumValidatorStyle enum values. + @param precision + The number of decimal digits after the decimal separator to show + and accept. + */ + //@{ + wxFloatingPointValidator(ValueType *value = NULL, + int style = wxNUM_VAL_DEFAULT); + wxFloatingPointValidator(int precision, + ValueType *value = NULL, + int style = wxNUM_VAL_DEFAULT); + //@} + + + /** + Set precision. + + Precision is the number of digits shown (and accepted on input) + after the decimal point. By default this is set to the maximal + precision supported by the type handled by the validator in its + constructor. + */ + void SetPrecision(unsigned precision); +}; + +/** + Creates a wxFloatingPointValidator object with automatic type deduction. + + Similarly to wxMakeIntegerValidator(), this function allows to avoid + explicitly specifying the validator type. + + @since 2.9.2 + */ +//@{ +template +inline wxFloatingPointValidator +wxMakeFloatingPointValidator(T *value, int style = wxNUM_VAL_DEFAULT); + +template +inline wxFloatingPointValidator +wxMakeFloatingPointValidator(int precision, + T *value, int style = wxNUM_VAL_DEFAULT); +//@} diff --git a/interface/wx/valtext.h b/interface/wx/valtext.h index b4f9e04912..f0d03f5f97 100644 --- a/interface/wx/valtext.h +++ b/interface/wx/valtext.h @@ -77,7 +77,8 @@ enum wxTextValidatorStyle @library{wxcore} @category{validator} - @see @ref overview_validator, wxValidator, wxGenericValidator + @see @ref overview_validator, wxValidator, wxGenericValidator, + wxIntegerValidator, wxFloatingPointValidator */ class wxTextValidator : public wxValidator { diff --git a/samples/validate/validate.cpp b/samples/validate/validate.cpp index 344f719d14..59c9d95036 100644 --- a/samples/validate/validate.cpp +++ b/samples/validate/validate.cpp @@ -31,6 +31,7 @@ #include "wx/sizer.h" #include "wx/valgen.h" #include "wx/valtext.h" +#include "wx/valnum.h" #ifndef __WXMSW__ #include "../sample.xpm" @@ -63,6 +64,8 @@ MyData::MyData() m_string = wxT("Spaces are invalid here"); m_string2 = "Valid text"; m_listbox_choices.Add(0); + m_intValue = 0; + m_doubleValue = 12354.31; } // ---------------------------------------------------------------------------- @@ -215,6 +218,9 @@ void MyFrame::OnTestDialog(wxCommandEvent& WXUNUSED(event)) m_listbox->Append(wxString(wxT("checkbox: ")) + checkbox_state); m_listbox->Append(wxString(wxT("combobox: ")) + g_data.m_combobox_choice); m_listbox->Append(wxString(wxT("radiobox: ")) + g_radiobox_choices[g_data.m_radiobox_choice]); + + m_listbox->Append(wxString::Format("integer value: %d", g_data.m_intValue)); + m_listbox->Append(wxString::Format("double value: %.3f", g_data.m_doubleValue)); } } @@ -296,6 +302,49 @@ MyDialog::MyDialog( wxWindow *parent, const wxString& title, btn->AddButton(new wxButton(this, wxID_CANCEL)); btn->Realize(); + // setup a sizer with the controls for numeric validators + // ------------------------------------------------------ + + wxIntegerValidator valInt(&g_data.m_intValue, + wxNUM_VAL_THOUSANDS_SEPARATOR | + wxNUM_VAL_ZERO_AS_BLANK); + valInt.SetMin(0); // Only allow positive numbers + + m_numericTextInt = new wxTextCtrl + ( + this, + wxID_ANY, + "", + wxDefaultPosition, + wxDefaultSize, + wxTE_RIGHT, + valInt + ); + m_numericTextInt->SetToolTip("uses wxIntegerValidator to accept positive " + "integers only"); + + m_numericTextDouble = new wxTextCtrl + ( + this, + wxID_ANY, + "", + wxDefaultPosition, + wxDefaultSize, + wxTE_RIGHT, + wxMakeFloatingPointValidator + ( + 3, + &g_data.m_doubleValue, + wxNUM_VAL_THOUSANDS_SEPARATOR | + wxNUM_VAL_NO_TRAILING_ZEROES + ) + ); + m_numericTextDouble->SetToolTip("uses wxFloatingPointValidator with 3 decimals"); + wxBoxSizer *numSizer = new wxBoxSizer( wxHORIZONTAL ); + numSizer->Add( m_numericTextInt, 1, wxALL, 10 ); + numSizer->Add( m_numericTextDouble, 1, wxALL, 10 ); + + // setup the main sizer // -------------------- @@ -310,6 +359,8 @@ MyDialog::MyDialog( wxWindow *parent, const wxString& title, wxGenericValidator(&g_data.m_radiobox_choice)), 0, wxGROW | wxLEFT|wxBOTTOM|wxRIGHT, 10); + mainsizer->Add( numSizer, 0, wxGROW | wxALL ); + mainsizer->Add(btn, 0, wxGROW | wxALL, 10); SetSizer(mainsizer); diff --git a/samples/validate/validate.h b/samples/validate/validate.h index dfef4c78af..beb50de15d 100644 --- a/samples/validate/validate.h +++ b/samples/validate/validate.h @@ -52,6 +52,9 @@ public: bool TransferDataToWindow(); wxTextCtrl *m_text; wxComboBox *m_combobox; + + wxTextCtrl *m_numericTextInt; + wxTextCtrl *m_numericTextDouble; }; class MyData @@ -72,6 +75,10 @@ public: // the string entered in the combobox's text-edit field. wxString m_combobox_choice; + // variables handled by wxNumericTextValidator + int m_intValue; + double m_doubleValue; + bool m_checkbox_state; int m_radiobox_choice; }; diff --git a/src/common/valnum.cpp b/src/common/valnum.cpp new file mode 100644 index 0000000000..8a84e4f7f3 --- /dev/null +++ b/src/common/valnum.cpp @@ -0,0 +1,299 @@ +///////////////////////////////////////////////////////////////////////////// +// 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 diff --git a/src/generic/grideditors.cpp b/src/generic/grideditors.cpp index 57f01972b3..6574ed6cb8 100644 --- a/src/generic/grideditors.cpp +++ b/src/generic/grideditors.cpp @@ -28,12 +28,12 @@ #include "wx/textctrl.h" #include "wx/checkbox.h" #include "wx/combobox.h" - #include "wx/valtext.h" #include "wx/intl.h" #include "wx/math.h" #include "wx/listbox.h" #endif +#include "wx/valnum.h" #include "wx/textfile.h" #include "wx/spinctrl.h" #include "wx/tokenzr.h" @@ -660,7 +660,7 @@ void wxGridCellNumberEditor::Create(wxWindow* parent, wxGridCellTextEditor::Create(parent, id, evtHandler); #if wxUSE_VALIDATORS - Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + Text()->SetValidator(wxIntegerValidator()); #endif } } @@ -875,7 +875,7 @@ void wxGridCellFloatEditor::Create(wxWindow* parent, wxGridCellTextEditor::Create(parent, id, evtHandler); #if wxUSE_VALIDATORS - Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + Text()->SetValidator(wxFloatingPointValidator(m_precision)); #endif } diff --git a/tests/Makefile.in b/tests/Makefile.in index 53b6e4dcc1..9c5c25bff8 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -213,6 +213,7 @@ TEST_GUI_OBJECTS = \ test_gui_settings.o \ test_gui_socket.o \ test_gui_boxsizer.o \ + test_gui_valnum.o \ test_gui_clientsize.o \ test_gui_setsize.o \ test_gui_xrctest.o @@ -866,6 +867,9 @@ test_gui_socket.o: $(srcdir)/net/socket.cpp $(TEST_GUI_ODEP) test_gui_boxsizer.o: $(srcdir)/sizers/boxsizer.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/sizers/boxsizer.cpp +test_gui_valnum.o: $(srcdir)/validators/valnum.cpp $(TEST_GUI_ODEP) + $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/validators/valnum.cpp + test_gui_clientsize.o: $(srcdir)/window/clientsize.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/window/clientsize.cpp diff --git a/tests/makefile.bcc b/tests/makefile.bcc index 53a429011f..15598e5f18 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -198,6 +198,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_settings.obj \ $(OBJS)\test_gui_socket.obj \ $(OBJS)\test_gui_boxsizer.obj \ + $(OBJS)\test_gui_valnum.obj \ $(OBJS)\test_gui_clientsize.obj \ $(OBJS)\test_gui_setsize.obj \ $(OBJS)\test_gui_xrctest.obj @@ -912,6 +913,9 @@ $(OBJS)\test_gui_socket.obj: .\net\socket.cpp $(OBJS)\test_gui_boxsizer.obj: .\sizers\boxsizer.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\sizers\boxsizer.cpp +$(OBJS)\test_gui_valnum.obj: .\validators\valnum.cpp + $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\validators\valnum.cpp + $(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\window\clientsize.cpp diff --git a/tests/makefile.gcc b/tests/makefile.gcc index 505525af14..8146997c8b 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -191,6 +191,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_settings.o \ $(OBJS)\test_gui_socket.o \ $(OBJS)\test_gui_boxsizer.o \ + $(OBJS)\test_gui_valnum.o \ $(OBJS)\test_gui_clientsize.o \ $(OBJS)\test_gui_setsize.o \ $(OBJS)\test_gui_xrctest.o @@ -893,6 +894,9 @@ $(OBJS)\test_gui_socket.o: ./net/socket.cpp $(OBJS)\test_gui_boxsizer.o: ./sizers/boxsizer.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\test_gui_valnum.o: ./validators/valnum.cpp + $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\test_gui_clientsize.o: ./window/clientsize.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< diff --git a/tests/makefile.vc b/tests/makefile.vc index 233b854b2f..a18a3dec1a 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -193,6 +193,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_settings.obj \ $(OBJS)\test_gui_socket.obj \ $(OBJS)\test_gui_boxsizer.obj \ + $(OBJS)\test_gui_valnum.obj \ $(OBJS)\test_gui_clientsize.obj \ $(OBJS)\test_gui_setsize.obj \ $(OBJS)\test_gui_xrctest.obj @@ -1038,6 +1039,9 @@ $(OBJS)\test_gui_socket.obj: .\net\socket.cpp $(OBJS)\test_gui_boxsizer.obj: .\sizers\boxsizer.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\sizers\boxsizer.cpp +$(OBJS)\test_gui_valnum.obj: .\validators\valnum.cpp + $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\validators\valnum.cpp + $(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\window\clientsize.cpp diff --git a/tests/makefile.wat b/tests/makefile.wat index e35199ad19..e542ea03b9 100644 --- a/tests/makefile.wat +++ b/tests/makefile.wat @@ -433,6 +433,7 @@ TEST_GUI_OBJECTS = & $(OBJS)\test_gui_settings.obj & $(OBJS)\test_gui_socket.obj & $(OBJS)\test_gui_boxsizer.obj & + $(OBJS)\test_gui_valnum.obj & $(OBJS)\test_gui_clientsize.obj & $(OBJS)\test_gui_setsize.obj & $(OBJS)\test_gui_xrctest.obj @@ -951,6 +952,9 @@ $(OBJS)\test_gui_socket.obj : .AUTODEPEND .\net\socket.cpp $(OBJS)\test_gui_boxsizer.obj : .AUTODEPEND .\sizers\boxsizer.cpp $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $< +$(OBJS)\test_gui_valnum.obj : .AUTODEPEND .\validators\valnum.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $< + $(OBJS)\test_gui_clientsize.obj : .AUTODEPEND .\window\clientsize.cpp $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $< diff --git a/tests/strings/numformatter.cpp b/tests/strings/numformatter.cpp index 7d5971901e..7ab235bc81 100644 --- a/tests/strings/numformatter.cpp +++ b/tests/strings/numformatter.cpp @@ -31,18 +31,13 @@ public: { // We need to use a locale with known decimal point and which uses the // thousands separator for the tests to make sense. - wxLanguage lang; - if ( wxLocale::IsAvailable(wxLANGUAGE_ENGLISH_US) ) - lang = wxLANGUAGE_ENGLISH_US; - else if ( wxLocale::IsAvailable(wxLANGUAGE_ENGLISH_UK) ) - lang = wxLANGUAGE_ENGLISH_UK; - else + m_locale = new wxLocale(wxLANGUAGE_ENGLISH_UK, + wxLOCALE_DONT_LOAD_DEFAULT); + if ( !m_locale->IsOk() ) { + delete m_locale; m_locale = NULL; - return; } - - m_locale = new wxLocale(lang, wxLOCALE_DONT_LOAD_DEFAULT); } virtual ~NumFormatterTestCase() diff --git a/tests/test.bkl b/tests/test.bkl index e11e136054..33d577ece2 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -199,6 +199,7 @@ --> net/socket.cpp sizers/boxsizer.cpp + validators/valnum.cpp window/clientsize.cpp window/setsize.cpp xml/xrctest.cpp diff --git a/tests/test_test_gui.dsp b/tests/test_test_gui.dsp index 2ed004defb..6020cf61b4 100644 --- a/tests/test_test_gui.dsp +++ b/tests/test_test_gui.dsp @@ -517,6 +517,10 @@ SOURCE=.\controls\treectrltest.cpp # End Source File # Begin Source File +SOURCE=.\validators\valnum.cpp +# End Source File +# Begin Source File + SOURCE=.\controls\virtlistctrltest.cpp # End Source File # Begin Source File diff --git a/tests/test_vc7_test_gui.vcproj b/tests/test_vc7_test_gui.vcproj index 377614d36f..c4790f5855 100644 --- a/tests/test_vc7_test_gui.vcproj +++ b/tests/test_vc7_test_gui.vcproj @@ -821,6 +821,9 @@ RelativePath=".\controls\treectrltest.cpp"> + + + + diff --git a/tests/test_vc9_test_gui.vcproj b/tests/test_vc9_test_gui.vcproj index 958ea5d401..24e9b62a2e 100644 --- a/tests/test_vc9_test_gui.vcproj +++ b/tests/test_vc9_test_gui.vcproj @@ -1140,6 +1140,10 @@ > + + diff --git a/tests/validators/valnum.cpp b/tests/validators/valnum.cpp new file mode 100644 index 0000000000..271162965e --- /dev/null +++ b/tests/validators/valnum.cpp @@ -0,0 +1,286 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: tests/validators/valnum.cpp +// Purpose: Unit tests for numeric validators. +// Author: Vadim Zeitlin +// Created: 2011-01-18 +// RCS-ID: $Id$ +// Copyright: (c) 2011 Vadim Zeitlin +/////////////////////////////////////////////////////////////////////////////// + +#include "testprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/textctrl.h" + #include "wx/validate.h" +#endif // WX_PRECOMP + +#include "wx/valnum.h" + +#include "asserthelper.h" +#include "testableframe.h" +#include "wx/uiaction.h" + +class NumValidatorTestCase : public CppUnit::TestCase +{ +public: + NumValidatorTestCase() { } + + void setUp(); + void tearDown(); + +private: + CPPUNIT_TEST_SUITE( NumValidatorTestCase ); + CPPUNIT_TEST( TransferInt ); + CPPUNIT_TEST( TransferUnsigned ); + CPPUNIT_TEST( TransferFloat ); + CPPUNIT_TEST( ZeroAsBlank ); + CPPUNIT_TEST( NoTrailingZeroes ); + WXUISIM_TEST( Interactive ); + CPPUNIT_TEST_SUITE_END(); + + void TransferInt(); + void TransferUnsigned(); + void TransferFloat(); + void ZeroAsBlank(); + void NoTrailingZeroes(); +#if wxUSE_UIACTIONSIMULATOR + void Interactive(); +#endif // wxUSE_UIACTIONSIMULATOR + + wxTextCtrl *m_text; + + wxDECLARE_NO_COPY_CLASS(NumValidatorTestCase); +}; + +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( NumValidatorTestCase ); + +// also include in it's own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( NumValidatorTestCase, "NumValidatorTestCase" ); + +void NumValidatorTestCase::setUp() +{ + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY); +} + +void NumValidatorTestCase::tearDown() +{ + wxTheApp->GetTopWindow()->DestroyChildren(); +} + +void NumValidatorTestCase::TransferInt() +{ + int value = 0; + wxIntegerValidator valInt(&value); + valInt.SetWindow(m_text); + + CPPUNIT_ASSERT( valInt.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "0", m_text->GetValue() ); + + value = 17; + CPPUNIT_ASSERT( valInt.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "17", m_text->GetValue() ); + + + m_text->ChangeValue("foobar"); + CPPUNIT_ASSERT( !valInt.TransferFromWindow() ); + + m_text->ChangeValue("-234"); + CPPUNIT_ASSERT( valInt.TransferFromWindow() ); + CPPUNIT_ASSERT_EQUAL( -234, value ); + + m_text->ChangeValue("9223372036854775808"); // == LLONG_MAX + 1 + CPPUNIT_ASSERT( !valInt.TransferFromWindow() ); + + m_text->Clear(); + CPPUNIT_ASSERT( !valInt.TransferFromWindow() ); +} + +void NumValidatorTestCase::TransferUnsigned() +{ + unsigned value = 0; + wxIntegerValidator valUnsigned(&value); + valUnsigned.SetWindow(m_text); + + CPPUNIT_ASSERT( valUnsigned.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "0", m_text->GetValue() ); + + value = 17; + CPPUNIT_ASSERT( valUnsigned.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "17", m_text->GetValue() ); + + + m_text->ChangeValue("foobar"); + CPPUNIT_ASSERT( !valUnsigned.TransferFromWindow() ); + + m_text->ChangeValue("-234"); + CPPUNIT_ASSERT( !valUnsigned.TransferFromWindow() ); + + m_text->ChangeValue("234"); + CPPUNIT_ASSERT( valUnsigned.TransferFromWindow() ); + CPPUNIT_ASSERT_EQUAL( 234, value ); + + m_text->ChangeValue("18446744073709551616"); // == ULLONG_MAX + 1 + CPPUNIT_ASSERT( !valUnsigned.TransferFromWindow() ); + + m_text->Clear(); + CPPUNIT_ASSERT( !valUnsigned.TransferFromWindow() ); +} + +void NumValidatorTestCase::TransferFloat() +{ + float value = 0; + wxFloatingPointValidator valFloat(3, &value); + valFloat.SetWindow(m_text); + + CPPUNIT_ASSERT( valFloat.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "0.000", m_text->GetValue() ); + + value = 1.234f; + CPPUNIT_ASSERT( valFloat.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "1.234", m_text->GetValue() ); + + value = 1.2345678f; + CPPUNIT_ASSERT( valFloat.TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "1.235", m_text->GetValue() ); + + + m_text->ChangeValue("foobar"); + CPPUNIT_ASSERT( !valFloat.TransferFromWindow() ); + + m_text->ChangeValue("-234.567"); + CPPUNIT_ASSERT( valFloat.TransferFromWindow() ); + CPPUNIT_ASSERT_EQUAL( -234.567f, value ); + + m_text->Clear(); + CPPUNIT_ASSERT( !valFloat.TransferFromWindow() ); +} + +void NumValidatorTestCase::ZeroAsBlank() +{ + long value = 0; + m_text->SetValidator( + wxMakeIntegerValidator(&value, wxNUM_VAL_ZERO_AS_BLANK)); + + wxValidator * const val = m_text->GetValidator(); + + CPPUNIT_ASSERT( val->TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "", m_text->GetValue() ); + + value++; + CPPUNIT_ASSERT( val->TransferFromWindow() ); + CPPUNIT_ASSERT_EQUAL( 0, value ); +} + +void NumValidatorTestCase::NoTrailingZeroes() +{ + double value = 1.2; + m_text->SetValidator( + wxMakeFloatingPointValidator(3, &value, wxNUM_VAL_NO_TRAILING_ZEROES)); + + wxValidator * const val = m_text->GetValidator(); + + CPPUNIT_ASSERT( val->TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "1.2", m_text->GetValue() ); + + value = 1.234; + CPPUNIT_ASSERT( val->TransferToWindow() ); + CPPUNIT_ASSERT_EQUAL( "1.234", m_text->GetValue() ); +} + +#if wxUSE_UIACTIONSIMULATOR + +void NumValidatorTestCase::Interactive() +{ + // Set a locale using comma as thousands separator character. + wxLocale loc(wxLANGUAGE_ENGLISH_UK, wxLOCALE_DONT_LOAD_DEFAULT); + + m_text->SetValidator( + wxIntegerValidator(NULL, wxNUM_VAL_THOUSANDS_SEPARATOR)); + + // Create a sibling text control to be able to switch focus and thus + // trigger the control validation/normalization. + wxTextCtrl * const text2 = new wxTextCtrl(m_text->GetParent(), wxID_ANY); + text2->Move(10, 80); // Just to see it better while debugging... + wxFloatingPointValidator valFloat(3); + valFloat.SetRange(-10., 10.); + text2->SetValidator(valFloat); + + wxUIActionSimulator sim; + + // Entering '-' in a control with positive range is not allowed. + m_text->SetFocus(); + sim.Char('-'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "", m_text->GetValue() ); + + // Neither is entering '.' or any non-digit character. + sim.Text(".a+/"); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "", m_text->GetValue() ); + + // Entering digits should work though and after leaving the control the + // contents should be normalized. + sim.Text("1234567"); + wxYield(); + text2->SetFocus(); + wxYield(); + if ( loc.IsOk() ) + CPPUNIT_ASSERT_EQUAL( "1,234,567", m_text->GetValue() ); + else + CPPUNIT_ASSERT_EQUAL( "1234567", m_text->GetValue() ); + + + // Entering both '-' and '.' in this control should work but only in the + // correct order. + sim.Char('-'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "-", text2->GetValue() ); + + text2->SetInsertionPoint(0); + sim.Char('.'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "-", text2->GetValue() ); + + text2->SetInsertionPointEnd(); + sim.Char('.'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "-.", text2->GetValue() ); + + // Adding up to three digits after the point should work. + sim.Text("987"); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "-.987", text2->GetValue() ); + + // But no more. + sim.Text("654"); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "-.987", text2->GetValue() ); + + // We can remove one digit and another one though. + sim.Char(WXK_BACK); + sim.Char(WXK_BACK); + sim.Char('6'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "-.96", text2->GetValue() ); + + + // Also test the range constraint. + text2->Clear(); + + sim.Char('9'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "9", text2->GetValue() ); + + sim.Char('9'); + wxYield(); + CPPUNIT_ASSERT_EQUAL( "9", text2->GetValue() ); +} + +#endif // wxUSE_UIACTIONSIMULATOR -- 2.45.2