From 3e1512cdfecd2c531567e6603083d9c3968216c7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 21 Jul 2007 23:47:22 +0000 Subject: [PATCH] added support for user-defined types to wxConfig (patch 1753875) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47634 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/config.tex | 35 ++++++-- include/wx/confbase.h | 70 ++++++++++++++-- src/common/config.cpp | 34 ++++---- tests/config/config.cpp | 175 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 283 insertions(+), 32 deletions(-) create mode 100644 tests/config/config.cpp diff --git a/docs/changes.txt b/docs/changes.txt index 1e06a74e89..75824c0085 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -106,6 +106,7 @@ Major new features in this release All: +- Added support for user-defined types to wxConfig (Marcin Wojdyr) - Added wxJoin() and wxSplit() functions (Francesco Montorsi) - Added wxMutex::LockTimeout() (Aleksandr Napylov) - Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev) diff --git a/docs/latex/wx/config.tex b/docs/latex/wx/config.tex index 5955677d54..61c2136e6a 100644 --- a/docs/latex/wx/config.tex +++ b/docs/latex/wx/config.tex @@ -262,13 +262,11 @@ These function are the core of wxConfigBase class: they allow you to read and write config file data. All {\it Read} function take a default value which will be returned if the specified key is not found in the config file. -Currently, only two types of data are supported: string and long (but it might -change in the near future). To work with other types: for {\it int} or {\it -bool} you can work with function taking/returning {\it long} and just use the -casts. Better yet, just use {\it long} for all variables which you're going to -save in the config file: chances are that {\tt sizeof(bool) == sizeof(int) == sizeof(long)} anyhow on your system. For {\it float}, {\it double} and, in -general, any other type you'd have to translate them to/from string -representation and use string functions. +Currently, supported types of data are: +\helpref{wxString}{wxstring}, {\it long}, {\it double}, {\it bool}, +\helpref{wxColour}{wxcolour} and any other types, +for which functions \helpref{wxToString}{wxtostring} +and \helpref{wxFromString}{wxfromstring} are defined. Try not to read long values into string variables and vice versa: although it just might work with wxFileConfig, you will get a system error with @@ -721,6 +719,23 @@ not found, {\it defaultVal} is used instead. Reads a binary block, returning \true if the value was found. If the value was not found, {\it buf} is not changed. +\constfunc{bool}{Read}{\param{const wxString\& }{ key}, \param{T*}{ value}} + +Reads a value of type T, for which function +\helpref{wxFromString}{wxfromstring} is defined, +returning \true if the value was found. +If the value was not found, {\it value} is not changed. + +\constfunc{bool}{Read}{\param{const wxString\& }{ key}, \param{T*}{ value}, + \param{T const\& }{ defaultVal}} + +Reads a value of type T, for which function +\helpref{wxFromString}{wxfromstring} is defined, +returning \true if the value was found. +If the value was not found, {\it defaultVal} is used instead. + +bool Read(const wxString& key, T* value) const; + \pythonnote{In place of a single overloaded method name, wxPython implements the following methods:\par \indented{2cm}{\begin{twocollist} @@ -813,7 +828,11 @@ value}} \func{bool}{Write}{\param{const wxString\& }{ key}, \param{const wxMemoryBuffer\&}{ buf}} -These functions write the specified value to the config file and return \true on success. +\func{bool}{Write}{\param{const wxString\& }{ key}, \param{const T\&}{ buf}} + +These functions write the specified value to the config file and return \true +on success. In the last one, function \helpref{wxToString}{wxtostring} must be +defined for type {\it T}. \pythonnote{In place of a single overloaded method name, wxPython implements the following methods:\par diff --git a/include/wx/confbase.h b/include/wx/confbase.h index 39d06305b8..bcba0a1eea 100644 --- a/include/wx/confbase.h +++ b/include/wx/confbase.h @@ -166,7 +166,7 @@ public: bool Read(const wxString& key, long *pl) const; bool Read(const wxString& key, long *pl, long defVal) const; - // read an int + // read an int (wrapper around `long' version) bool Read(const wxString& key, int *pi) const; bool Read(const wxString& key, int *pi, int defVal) const; @@ -185,12 +185,45 @@ public: // no default version since it does not make sense for binary data #endif // wxUSE_BASE64 + + // read other types, for which wxFromString is defined + template + bool Read(const wxString& key, T* value) const + { + wxString s; + if ( !Read(key, &s) ) + return false; + return wxFromString(s, value); + } + + template + bool Read(const wxString& key, T* value, const T& defVal) const + { + const bool found = Read(key, value); + if ( !found ) + { + if (IsRecordingDefaults()) + ((wxConfigBase *)this)->Write(key, defVal); + *value = defVal; + } + return found; + } + // convenience functions returning directly the value (we don't have them for // int/double/bool as there would be ambiguities with the long one then) wxString Read(const wxString& key, const wxString& defVal = wxEmptyString) const { wxString s; (void)Read(key, &s, defVal); return s; } + // we have to provide a separate version for C strings as otherwise the + // template Read() would be used + wxString Read(const wxString& key, const char* defVal) const + { return Read(key, wxString(defVal)); } +#if wxUSE_WCHAR_T + wxString Read(const wxString& key, const wchar_t* defVal) const + { return Read(key, wxString(defVal)); } +#endif + long Read(const wxString& key, long defVal) const { long l; (void)Read(key, &l, defVal); return l; } @@ -201,9 +234,6 @@ public: bool Write(const wxString& key, long value) { return DoWriteLong(key, value); } - bool Write(const wxString& key, int value) - { return DoWriteInt(key, value); } - bool Write(const wxString& key, double value) { return DoWriteDouble(key, value); } @@ -219,11 +249,41 @@ public: // would be converted to bool and not to wxString as expected! bool Write(const wxString& key, const char *value) { return Write(key, wxString(value)); } + bool Write(const wxString& key, const unsigned char *value) + { return Write(key, wxString(value)); } #if wxUSE_WCHAR_T bool Write(const wxString& key, const wchar_t *value) { return Write(key, wxString(value)); } #endif + + // we also have to provide specializations for other types which we want to + // handle using the specialized DoWriteXXX() instead of the generic template + // version below + bool Write(const wxString& key, short value) + { return DoWriteLong(key, value); } + + bool Write(const wxString& key, unsigned short value) + { return DoWriteLong(key, value); } + + bool Write(const wxString& key, unsigned int value) + { return DoWriteLong(key, value); } + + bool Write(const wxString& key, int value) + { return DoWriteLong(key, value); } + + bool Write(const wxString& key, unsigned long value) + { return DoWriteLong(key, value); } + + bool Write(const wxString& key, float value) + { return DoWriteDouble(key, value); } + + + // for other types, use wxToString() + template + bool Write(const wxString& key, T const& value) + { return Write(key, wxToString(value)); } + // permanently writes all changes virtual bool Flush(bool bCurrentOnly = false) = 0; @@ -283,7 +343,6 @@ protected: // do read/write the values of different types virtual bool DoReadString(const wxString& key, wxString *pStr) const = 0; virtual bool DoReadLong(const wxString& key, long *pl) const = 0; - virtual bool DoReadInt(const wxString& key, int *pi) const; virtual bool DoReadDouble(const wxString& key, double* val) const; virtual bool DoReadBool(const wxString& key, bool* val) const; #if wxUSE_BASE64 @@ -292,7 +351,6 @@ protected: virtual bool DoWriteString(const wxString& key, const wxString& value) = 0; virtual bool DoWriteLong(const wxString& key, long value) = 0; - virtual bool DoWriteInt(const wxString& key, int value); virtual bool DoWriteDouble(const wxString& key, double value); virtual bool DoWriteBool(const wxString& key, bool value); #if wxUSE_BASE64 diff --git a/src/common/config.cpp b/src/common/config.cpp index c4ae2ed8d1..adaa109546 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -156,29 +156,32 @@ wxConfigBase *wxConfigBase::Create() IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars) IMPLEMENT_READ_FOR_TYPE(Long, long, long, long) -IMPLEMENT_READ_FOR_TYPE(Int, int, int, int) IMPLEMENT_READ_FOR_TYPE(Double, double, double, double) IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool) #undef IMPLEMENT_READ_FOR_TYPE -// the DoReadXXX() for the other types have implementation in the base class -// but can be overridden in the derived ones -bool wxConfigBase::DoReadInt(const wxString& key, int *pi) const +// int is stored as long +bool wxConfigBase::Read(const wxString& key, int *pi) const { - wxCHECK_MSG( pi, false, _T("wxConfig::Read(): NULL parameter") ); - - long l; - if ( !DoReadLong(key, &l) ) - return false; - - wxASSERT_MSG( l < INT_MAX, _T("overflow in wxConfig::DoReadInt") ); - + long l = *pi; + bool r = Read(key, &l); + wxASSERT_MSG( l < INT_MAX, _T("int overflow in wxConfig::Read") ); *pi = (int)l; + return r; +} - return true; +bool wxConfigBase::Read(const wxString& key, int *pi, int defVal) const +{ + long l = *pi; + bool r = Read(key, &l, defVal); + wxASSERT_MSG( l < INT_MAX, _T("int overflow in wxConfig::Read") ); + *pi = (int)l; + return r; } +// the DoReadXXX() for the other types have implementation in the base class +// but can be overridden in the derived ones bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const { wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); @@ -225,11 +228,6 @@ bool wxConfigBase::DoWriteDouble(const wxString& key, double val) return DoWriteString(key, wxString::Format(_T("%g"), val)); } -bool wxConfigBase::DoWriteInt(const wxString& key, int value) -{ - return DoWriteLong(key, (long)value); -} - bool wxConfigBase::DoWriteBool(const wxString& key, bool value) { return DoWriteLong(key, value ? 1l : 0l); diff --git a/tests/config/config.cpp b/tests/config/config.cpp new file mode 100644 index 0000000000..1fc9a47dc5 --- /dev/null +++ b/tests/config/config.cpp @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: tests/config/config.cpp +// Purpose: wxConfig unit test +// Author: Marcin Wojdyr +// Created: 2007-07-07 +// RCS-ID: $Id$ +// Copyright: (c) 2007 Marcin Wojdyr +/////////////////////////////////////////////////////////////////////////////// + +// see also tests/fileconf/fileconftest.cpp for wxFileConfig specific tests + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "testprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif // WX_PRECOMP + +#include "wx/config.h" +#include "wx/colour.h" + +// -------------------------------------------------------------------------- +// test class +// -------------------------------------------------------------------------- + +class ConfigTestCase : public CppUnit::TestCase +{ +public: + ConfigTestCase() {} + +private: + CPPUNIT_TEST_SUITE( ConfigTestCase ); + CPPUNIT_TEST( ReadWriteLocalTest ); + CPPUNIT_TEST( RecordingDefaultsTest ); + CPPUNIT_TEST_SUITE_END(); + + void ReadWriteLocalTest(); + void RecordingDefaultsTest(); + + DECLARE_NO_COPY_CLASS(ConfigTestCase) +}; + +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( ConfigTestCase ); + +// also include in it's own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ConfigTestCase, "ConfigTestCase" ); + +void ConfigTestCase::ReadWriteLocalTest() +{ + wxString app = wxT("wxConfigTestCase"); + wxString vendor = wxT("wxWidgets"); + wxConfig *config = new wxConfig(app, vendor, wxT(""), wxT(""), + wxCONFIG_USE_LOCAL_FILE); + config->DeleteAll(); + config->Write(wxT("string1"), wxT("abc")); + config->Write(wxT("string2"), wxString(wxT("def"))); + config->Write(wxT("int1"), 123); + config->Write(wxString(wxT("long1")), 234L); + config->Write(wxT("double1"), 345.67); + config->Write(wxT("bool1"), true); + config->Write(wxT("color1"), wxColour(11,22,33,44)); + config->Flush(); + delete config; + + config = new wxConfig(app, vendor, wxT(""), wxT(""), + wxCONFIG_USE_LOCAL_FILE); + wxString string1 = config->Read(wxT("string1")); + CPPUNIT_ASSERT( string1 == wxT("abc") ); + string1 = config->Read(wxT("string1"), wxT("defaultvalue")); + CPPUNIT_ASSERT( string1 == wxT("abc") ); + wxString string2; + bool r = config->Read(wxT("string2"), &string2); + CPPUNIT_ASSERT( r == true ); + CPPUNIT_ASSERT( string2 == wxT("def") ); + r = config->Read(wxT("string2"), &string2, wxT("defaultvalue")); + CPPUNIT_ASSERT( r == true ); + CPPUNIT_ASSERT( string2 == wxT("def") ); + int int1 = config->Read(wxT("int1"), 5); + CPPUNIT_ASSERT( int1 == 123 ); + long long1; + r = config->Read(wxT("long1"), &long1); + CPPUNIT_ASSERT( r == true ); + CPPUNIT_ASSERT( long1 == 234 ); + bool bool1; + r = config->Read(wxT("foo"), &bool1); + CPPUNIT_ASSERT( r == false ); + r = config->Read(wxT("bool1"), &bool1); + CPPUNIT_ASSERT( r == true ); + CPPUNIT_ASSERT( bool1 == true ); + wxColour color1; + r = config->Read(wxT("color1"), &color1); + CPPUNIT_ASSERT( r == true ); + CPPUNIT_ASSERT( color1 == wxColour(11,22,33,44) ); + config->DeleteAll(); + delete config; +} + +void ConfigTestCase::RecordingDefaultsTest() +{ + wxString app = wxT("wxConfigTestCaseRD"); + wxString vendor = wxT("wxWidgets"); + wxConfig *config = new wxConfig(app, vendor, wxT(""), wxT(""), + wxCONFIG_USE_LOCAL_FILE); + config->DeleteAll(); + config->SetRecordDefaults(false); // by default it is false + wxString string1, string2, string3, string4; + string1 = config->Read(wxT("string1"), wxT("abc")); + string2 = config->Read(wxT("string2"), wxString(wxT("def"))); + config->Read(wxT("string3"), &string3, wxT("abc")); + config->Read(wxT("string4"), &string4, wxString(wxT("def"))); + int int1, int2; + config->Read(wxT("int1"), &int1, 123); + int2 = config->Read(wxT("int2"), 1234); + long long1; + config->Read(wxString(wxT("long1")), &long1, 234L); + double double1; + config->Read(wxT("double1"), &double1, 345.67); + bool bool1; + config->Read(wxT("bool1"), &bool1, true); + wxColour color1; + config->Read(wxT("color1"), &color1, wxColour(11,22,33,44)); + + CPPUNIT_ASSERT ( config->GetNumberOfEntries() == 0 ); + + config->SetRecordDefaults(true); + + bool r; + string1 = config->Read(wxT("string1"), wxT("abc")); + string2 = config->Read(wxT("string2"), wxString(wxT("def"))); + r = config->Read(wxT("string3"), &string3, wxT("abc")); + CPPUNIT_ASSERT( r == false ); + r = config->Read(wxT("string4"), &string4, wxString(wxT("def"))); + CPPUNIT_ASSERT( r == false ); + r = config->Read(wxT("int1"), &int1, 123); + CPPUNIT_ASSERT( r == false ); + int2 = config->Read(wxT("int2"), 1234); + r = config->Read(wxString(wxT("long1")), &long1, 234L); + CPPUNIT_ASSERT( r == false ); + r = config->Read(wxT("double1"), &double1, 345.67); + CPPUNIT_ASSERT( r == false ); + r = config->Read(wxT("bool1"), &bool1, true); + CPPUNIT_ASSERT( r == false ); + r = config->Read(wxT("color1"), &color1, wxColour(11,22,33,44)); + CPPUNIT_ASSERT( r == false ); + + CPPUNIT_ASSERT ( config->GetNumberOfEntries() == 10 ); + + r = config->Read(wxT("string3"), &string3, wxT("abc")); + CPPUNIT_ASSERT( r == true ); + r = config->Read(wxT("string4"), &string4, wxString(wxT("def"))); + CPPUNIT_ASSERT( r == true ); + r = config->Read(wxT("int1"), &int1, 123); + CPPUNIT_ASSERT( r == true ); + r = config->Read(wxString(wxT("long1")), &long1, 234L); + CPPUNIT_ASSERT( r == true ); + r = config->Read(wxT("double1"), &double1, 345.67); + CPPUNIT_ASSERT( r == true ); + r = config->Read(wxT("bool1"), &bool1, true); + CPPUNIT_ASSERT( r == true ); + r = config->Read(wxT("color1"), &color1, wxColour(11,22,33,44)); + CPPUNIT_ASSERT( r == true ); + + config->DeleteAll(); + delete config; +} + + -- 2.45.2