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)
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
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}
\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
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;
// no default version since it does not make sense for binary data
#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
// 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; }
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); }
// 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 <typename T>
+ bool Write(const wxString& key, T const& value)
+ { return Write(key, wxToString(value)); }
+
// permanently writes all changes
virtual bool Flush(bool bCurrentOnly = false) = 0;
// 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
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
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") );
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);
--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// 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;
+}
+
+