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
This commit is contained in:
Vadim Zeitlin
2007-07-21 23:47:22 +00:00
parent d2001a563b
commit 3e1512cdfe
5 changed files with 284 additions and 33 deletions

View File

@@ -106,6 +106,7 @@ Major new features in this release
All: All:
- Added support for user-defined types to wxConfig (Marcin Wojdyr)
- Added wxJoin() and wxSplit() functions (Francesco Montorsi) - Added wxJoin() and wxSplit() functions (Francesco Montorsi)
- Added wxMutex::LockTimeout() (Aleksandr Napylov) - Added wxMutex::LockTimeout() (Aleksandr Napylov)
- Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev) - Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev)

View File

@@ -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 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. 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 Currently, supported types of data are:
change in the near future). To work with other types: for {\it int} or {\it \helpref{wxString}{wxstring}, {\it long}, {\it double}, {\it bool},
bool} you can work with function taking/returning {\it long} and just use the \helpref{wxColour}{wxcolour} and any other types,
casts. Better yet, just use {\it long} for all variables which you're going to for which functions \helpref{wxToString}{wxtostring}
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 and \helpref{wxFromString}{wxfromstring} are defined.
general, any other type you'd have to translate them to/from string
representation and use string functions.
Try not to read long values into string variables and vice versa: although it 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 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 Reads a binary block, returning \true if the value was found. If the value was
not found, {\it buf} is not changed. 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 \pythonnote{In place of a single overloaded method name, wxPython
implements the following methods:\par implements the following methods:\par
\indented{2cm}{\begin{twocollist} \indented{2cm}{\begin{twocollist}
@@ -813,7 +828,11 @@ value}}
\func{bool}{Write}{\param{const wxString\& }{ key}, \param{const wxMemoryBuffer\&}{ buf}} \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 \pythonnote{In place of a single overloaded method name, wxPython
implements the following methods:\par implements the following methods:\par

View File

@@ -166,7 +166,7 @@ public:
bool Read(const wxString& key, long *pl) const; bool Read(const wxString& key, long *pl) const;
bool Read(const wxString& key, long *pl, long defVal) 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) const;
bool Read(const wxString& key, int *pi, int defVal) 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 // no default version since it does not make sense for binary data
#endif // wxUSE_BASE64 #endif // wxUSE_BASE64
// read other types, for which wxFromString is defined
template <typename T>
bool Read(const wxString& key, T* value) const
{
wxString s;
if ( !Read(key, &s) )
return false;
return wxFromString(s, value);
}
template <typename T>
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 // 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) // int/double/bool as there would be ambiguities with the long one then)
wxString Read(const wxString& key, wxString Read(const wxString& key,
const wxString& defVal = wxEmptyString) const const wxString& defVal = wxEmptyString) const
{ wxString s; (void)Read(key, &s, defVal); return s; } { 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 Read(const wxString& key, long defVal) const
{ long l; (void)Read(key, &l, defVal); return l; } { long l; (void)Read(key, &l, defVal); return l; }
@@ -201,9 +234,6 @@ public:
bool Write(const wxString& key, long value) bool Write(const wxString& key, long value)
{ return DoWriteLong(key, value); } { return DoWriteLong(key, value); }
bool Write(const wxString& key, int value)
{ return DoWriteInt(key, value); }
bool Write(const wxString& key, double value) bool Write(const wxString& key, double value)
{ return DoWriteDouble(key, value); } { return DoWriteDouble(key, value); }
@@ -219,11 +249,41 @@ public:
// would be converted to bool and not to wxString as expected! // would be converted to bool and not to wxString as expected!
bool Write(const wxString& key, const char *value) bool Write(const wxString& key, const char *value)
{ return Write(key, wxString(value)); } { return Write(key, wxString(value)); }
bool Write(const wxString& key, const unsigned char *value)
{ return Write(key, wxString(value)); }
#if wxUSE_WCHAR_T #if wxUSE_WCHAR_T
bool Write(const wxString& key, const wchar_t *value) bool Write(const wxString& key, const wchar_t *value)
{ return Write(key, wxString(value)); } { return Write(key, wxString(value)); }
#endif #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 <typename T>
bool Write(const wxString& key, T const& value)
{ return Write(key, wxToString(value)); }
// permanently writes all changes // permanently writes all changes
virtual bool Flush(bool bCurrentOnly = false) = 0; virtual bool Flush(bool bCurrentOnly = false) = 0;
@@ -283,7 +343,6 @@ protected:
// do read/write the values of different types // do read/write the values of different types
virtual bool DoReadString(const wxString& key, wxString *pStr) const = 0; virtual bool DoReadString(const wxString& key, wxString *pStr) const = 0;
virtual bool DoReadLong(const wxString& key, long *pl) 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 DoReadDouble(const wxString& key, double* val) const;
virtual bool DoReadBool(const wxString& key, bool* val) const; virtual bool DoReadBool(const wxString& key, bool* val) const;
#if wxUSE_BASE64 #if wxUSE_BASE64
@@ -292,7 +351,6 @@ protected:
virtual bool DoWriteString(const wxString& key, const wxString& value) = 0; virtual bool DoWriteString(const wxString& key, const wxString& value) = 0;
virtual bool DoWriteLong(const wxString& key, long 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 DoWriteDouble(const wxString& key, double value);
virtual bool DoWriteBool(const wxString& key, bool value); virtual bool DoWriteBool(const wxString& key, bool value);
#if wxUSE_BASE64 #if wxUSE_BASE64

View File

@@ -156,29 +156,32 @@ wxConfigBase *wxConfigBase::Create()
IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars) IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars)
IMPLEMENT_READ_FOR_TYPE(Long, long, long, long) 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(Double, double, double, double)
IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool) IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool)
#undef IMPLEMENT_READ_FOR_TYPE #undef IMPLEMENT_READ_FOR_TYPE
// the DoReadXXX() for the other types have implementation in the base class // int is stored as long
// but can be overridden in the derived ones bool wxConfigBase::Read(const wxString& key, int *pi) const
bool wxConfigBase::DoReadInt(const wxString& key, int *pi) const
{ {
wxCHECK_MSG( pi, false, _T("wxConfig::Read(): NULL parameter") ); long l = *pi;
bool r = Read(key, &l);
long l; wxASSERT_MSG( l < INT_MAX, _T("int overflow in wxConfig::Read") );
if ( !DoReadLong(key, &l) )
return false;
wxASSERT_MSG( l < INT_MAX, _T("overflow in wxConfig::DoReadInt") );
*pi = (int)l; *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 bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const
{ {
wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); 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)); 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) bool wxConfigBase::DoWriteBool(const wxString& key, bool value)
{ {
return DoWriteLong(key, value ? 1l : 0l); return DoWriteLong(key, value ? 1l : 0l);

175
tests/config/config.cpp Normal file
View File

@@ -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;
}